From fb7737e949e31d8a71acee6bbb670f32dbd2a2c0 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Wed, 4 Mar 2015 20:01:14 -0600 Subject: hwspinlock/core: add device tree support This patch adds a new OF-friendly API of_hwspin_lock_get_id() for hwspinlock clients to use/request locks from a hwspinlock device instantiated through a device-tree blob. This new API can be used by hwspinlock clients to get the id for a specific lock using the phandle + args specifier, so that it can be requested using the available hwspin_lock_request_specific() API. Signed-off-by: Suman Anna Reviewed-by: Bjorn Andersson [small comment clarification] Signed-off-by: Ohad Ben-Cohen --- drivers/hwspinlock/hwspinlock_core.c | 79 ++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) (limited to 'drivers') diff --git a/drivers/hwspinlock/hwspinlock_core.c b/drivers/hwspinlock/hwspinlock_core.c index 461a0d739d75..52f708bcf77f 100644 --- a/drivers/hwspinlock/hwspinlock_core.c +++ b/drivers/hwspinlock/hwspinlock_core.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "hwspinlock_internal.h" @@ -257,6 +258,84 @@ void __hwspin_unlock(struct hwspinlock *hwlock, int mode, unsigned long *flags) } EXPORT_SYMBOL_GPL(__hwspin_unlock); +/** + * of_hwspin_lock_simple_xlate - translate hwlock_spec to return a lock id + * @bank: the hwspinlock device bank + * @hwlock_spec: hwlock specifier as found in the device tree + * + * This is a simple translation function, suitable for hwspinlock platform + * drivers that only has a lock specifier length of 1. + * + * Returns a relative index of the lock within a specified bank on success, + * or -EINVAL on invalid specifier cell count. + */ +static inline int +of_hwspin_lock_simple_xlate(const struct of_phandle_args *hwlock_spec) +{ + if (WARN_ON(hwlock_spec->args_count != 1)) + return -EINVAL; + + return hwlock_spec->args[0]; +} + +/** + * of_hwspin_lock_get_id() - get lock id for an OF phandle-based specific lock + * @np: device node from which to request the specific hwlock + * @index: index of the hwlock in the list of values + * + * This function provides a means for DT users of the hwspinlock module to + * get the global lock id of a specific hwspinlock using the phandle of the + * hwspinlock device, so that it can be requested using the normal + * hwspin_lock_request_specific() API. + * + * Returns the global lock id number on success, -EPROBE_DEFER if the hwspinlock + * device is not yet registered, -EINVAL on invalid args specifier value or an + * appropriate error as returned from the OF parsing of the DT client node. + */ +int of_hwspin_lock_get_id(struct device_node *np, int index) +{ + struct of_phandle_args args; + struct hwspinlock *hwlock; + struct radix_tree_iter iter; + void **slot; + int id; + int ret; + + ret = of_parse_phandle_with_args(np, "hwlocks", "#hwlock-cells", index, + &args); + if (ret) + return ret; + + /* Find the hwspinlock device: we need its base_id */ + ret = -EPROBE_DEFER; + rcu_read_lock(); + radix_tree_for_each_slot(slot, &hwspinlock_tree, &iter, 0) { + hwlock = radix_tree_deref_slot(slot); + if (unlikely(!hwlock)) + continue; + + if (hwlock->bank->dev->of_node == args.np) { + ret = 0; + break; + } + } + rcu_read_unlock(); + if (ret < 0) + goto out; + + id = of_hwspin_lock_simple_xlate(&args); + if (id < 0 || id >= hwlock->bank->num_locks) { + ret = -EINVAL; + goto out; + } + id += hwlock->bank->base_id; + +out: + of_node_put(args.np); + return ret ? ret : id; +} +EXPORT_SYMBOL_GPL(of_hwspin_lock_get_id); + static int hwspin_lock_register_single(struct hwspinlock *hwlock, int id) { struct hwspinlock *tmp; -- cgit v1.2.3-70-g09d2 From 65bd4341d61678494ea14994d0d7df73644ca014 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Wed, 4 Mar 2015 20:01:16 -0600 Subject: hwspinlock/omap: add support for dt nodes HwSpinlock IP is present only on OMAP4 and other newer SoCs, which are all device-tree boot only. This patch adds the base support for parsing the DT nodes, and removes the code dealing with the traditional platform device instantiation. Signed-off-by: Suman Anna [tony@atomide.com: ack for legacy file removal] Acked-by: Tony Lindgren [comment on the imperfect always-zero base_id] Signed-off-by: Ohad Ben-Cohen --- MAINTAINERS | 1 - arch/arm/mach-omap2/Makefile | 3 -- arch/arm/mach-omap2/hwspinlock.c | 60 ------------------------------------ drivers/hwspinlock/omap_hwspinlock.c | 18 ++++++++--- 4 files changed, 14 insertions(+), 68 deletions(-) delete mode 100644 arch/arm/mach-omap2/hwspinlock.c (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index 2e5bbc0d68b2..5fe8941ba12d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7095,7 +7095,6 @@ M: Ohad Ben-Cohen L: linux-omap@vger.kernel.org S: Maintained F: drivers/hwspinlock/omap_hwspinlock.c -F: arch/arm/mach-omap2/hwspinlock.c OMAP MMC SUPPORT M: Jarkko Lavinen diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index ec002bd4af77..9a2c88e56bae 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -277,8 +277,5 @@ obj-y += $(nand-m) $(nand-y) smsc911x-$(CONFIG_SMSC911X) := gpmc-smsc911x.o obj-y += $(smsc911x-m) $(smsc911x-y) -ifneq ($(CONFIG_HWSPINLOCK_OMAP),) -obj-y += hwspinlock.o -endif obj-y += common-board-devices.o twl-common.o dss-common.o diff --git a/arch/arm/mach-omap2/hwspinlock.c b/arch/arm/mach-omap2/hwspinlock.c deleted file mode 100644 index ef175acaeaa2..000000000000 --- a/arch/arm/mach-omap2/hwspinlock.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * OMAP hardware spinlock device initialization - * - * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com - * - * Contact: Simon Que - * Hari Kanigeri - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#include -#include -#include -#include - -#include "soc.h" -#include "omap_hwmod.h" -#include "omap_device.h" - -static struct hwspinlock_pdata omap_hwspinlock_pdata __initdata = { - .base_id = 0, -}; - -static int __init hwspinlocks_init(void) -{ - int retval = 0; - struct omap_hwmod *oh; - struct platform_device *pdev; - const char *oh_name = "spinlock"; - const char *dev_name = "omap_hwspinlock"; - - /* - * Hwmod lookup will fail in case our platform doesn't support the - * hardware spinlock module, so it is safe to run this initcall - * on all omaps - */ - oh = omap_hwmod_lookup(oh_name); - if (oh == NULL) - return -EINVAL; - - pdev = omap_device_build(dev_name, 0, oh, &omap_hwspinlock_pdata, - sizeof(struct hwspinlock_pdata)); - if (IS_ERR(pdev)) { - pr_err("Can't build omap_device for %s:%s\n", dev_name, - oh_name); - retval = PTR_ERR(pdev); - } - - return retval; -} -/* early board code might need to reserve specific hwspinlock instances */ -omap_postcore_initcall(hwspinlocks_init); diff --git a/drivers/hwspinlock/omap_hwspinlock.c b/drivers/hwspinlock/omap_hwspinlock.c index 47a275c6ece1..ad2f8cac8487 100644 --- a/drivers/hwspinlock/omap_hwspinlock.c +++ b/drivers/hwspinlock/omap_hwspinlock.c @@ -1,7 +1,7 @@ /* * OMAP hardware spinlock driver * - * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com + * Copyright (C) 2010-2015 Texas Instruments Incorporated - http://www.ti.com * * Contact: Simon Que * Hari Kanigeri @@ -27,6 +27,7 @@ #include #include #include +#include #include #include "hwspinlock_internal.h" @@ -80,14 +81,16 @@ static const struct hwspinlock_ops omap_hwspinlock_ops = { static int omap_hwspinlock_probe(struct platform_device *pdev) { - struct hwspinlock_pdata *pdata = pdev->dev.platform_data; + struct device_node *node = pdev->dev.of_node; struct hwspinlock_device *bank; struct hwspinlock *hwlock; struct resource *res; void __iomem *io_base; int num_locks, i, ret; + /* Only a single hwspinlock block device is supported */ + int base_id = 0; - if (!pdata) + if (!node) return -ENODEV; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -141,7 +144,7 @@ static int omap_hwspinlock_probe(struct platform_device *pdev) hwlock->priv = io_base + LOCK_BASE_OFFSET + sizeof(u32) * i; ret = hwspin_lock_register(bank, &pdev->dev, &omap_hwspinlock_ops, - pdata->base_id, num_locks); + base_id, num_locks); if (ret) goto reg_fail; @@ -174,11 +177,18 @@ static int omap_hwspinlock_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id omap_hwspinlock_of_match[] = { + { .compatible = "ti,omap4-hwspinlock", }, + { /* end */ }, +}; +MODULE_DEVICE_TABLE(of, omap_hwspinlock_of_match); + static struct platform_driver omap_hwspinlock_driver = { .probe = omap_hwspinlock_probe, .remove = omap_hwspinlock_remove, .driver = { .name = "omap_hwspinlock", + .of_match_table = of_match_ptr(omap_hwspinlock_of_match), }, }; -- cgit v1.2.3-70-g09d2 From 19a0f61224d2d91860fa8291ab63cb104ee86bdd Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Tue, 24 Mar 2015 10:11:05 -0700 Subject: hwspinlock: qcom: Add support for Qualcomm HW Mutex block Add driver for Qualcomm Hardware Mutex block found in many Qualcomm SoCs. Based on initial effort by Kumar Gala Signed-off-by: Bjorn Andersson Reviewed-by: Andy Gross Reviewed-by: Jeffrey Hugo Signed-off-by: Ohad Ben-Cohen --- drivers/hwspinlock/Kconfig | 12 +++ drivers/hwspinlock/Makefile | 1 + drivers/hwspinlock/qcom_hwspinlock.c | 181 +++++++++++++++++++++++++++++++++++ 3 files changed, 194 insertions(+) create mode 100644 drivers/hwspinlock/qcom_hwspinlock.c (limited to 'drivers') diff --git a/drivers/hwspinlock/Kconfig b/drivers/hwspinlock/Kconfig index 3612cb5b30b2..b5b4f52cef73 100644 --- a/drivers/hwspinlock/Kconfig +++ b/drivers/hwspinlock/Kconfig @@ -18,6 +18,18 @@ config HWSPINLOCK_OMAP If unsure, say N. +config HWSPINLOCK_QCOM + tristate "Qualcomm Hardware Spinlock device" + depends on ARCH_QCOM + select HWSPINLOCK + select MFD_SYSCON + help + Say y here to support the Qualcomm Hardware Mutex functionality, which + provides a synchronisation mechanism for the various processors on + the SoC. + + If unsure, say N. + config HSEM_U8500 tristate "STE Hardware Semaphore functionality" depends on ARCH_U8500 diff --git a/drivers/hwspinlock/Makefile b/drivers/hwspinlock/Makefile index 93eb64b66486..68f95d9a4855 100644 --- a/drivers/hwspinlock/Makefile +++ b/drivers/hwspinlock/Makefile @@ -4,4 +4,5 @@ obj-$(CONFIG_HWSPINLOCK) += hwspinlock_core.o obj-$(CONFIG_HWSPINLOCK_OMAP) += omap_hwspinlock.o +obj-$(CONFIG_HWSPINLOCK_QCOM) += qcom_hwspinlock.o obj-$(CONFIG_HSEM_U8500) += u8500_hsem.o diff --git a/drivers/hwspinlock/qcom_hwspinlock.c b/drivers/hwspinlock/qcom_hwspinlock.c new file mode 100644 index 000000000000..93b62e055ff6 --- /dev/null +++ b/drivers/hwspinlock/qcom_hwspinlock.c @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2015, Sony Mobile Communications AB + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hwspinlock_internal.h" + +#define QCOM_MUTEX_APPS_PROC_ID 1 +#define QCOM_MUTEX_NUM_LOCKS 32 + +static int qcom_hwspinlock_trylock(struct hwspinlock *lock) +{ + struct regmap_field *field = lock->priv; + u32 lock_owner; + int ret; + + ret = regmap_field_write(field, QCOM_MUTEX_APPS_PROC_ID); + if (ret) + return ret; + + ret = regmap_field_read(field, &lock_owner); + if (ret) + return ret; + + return lock_owner == QCOM_MUTEX_APPS_PROC_ID; +} + +static void qcom_hwspinlock_unlock(struct hwspinlock *lock) +{ + struct regmap_field *field = lock->priv; + u32 lock_owner; + int ret; + + ret = regmap_field_read(field, &lock_owner); + if (ret) { + pr_err("%s: unable to query spinlock owner\n", __func__); + return; + } + + if (lock_owner != QCOM_MUTEX_APPS_PROC_ID) { + pr_err("%s: spinlock not owned by us (actual owner is %d)\n", + __func__, lock_owner); + } + + ret = regmap_field_write(field, 0); + if (ret) + pr_err("%s: failed to unlock spinlock\n", __func__); +} + +static const struct hwspinlock_ops qcom_hwspinlock_ops = { + .trylock = qcom_hwspinlock_trylock, + .unlock = qcom_hwspinlock_unlock, +}; + +static const struct of_device_id qcom_hwspinlock_of_match[] = { + { .compatible = "qcom,sfpb-mutex" }, + { .compatible = "qcom,tcsr-mutex" }, + { } +}; +MODULE_DEVICE_TABLE(of, qcom_hwspinlock_of_match); + +static int qcom_hwspinlock_probe(struct platform_device *pdev) +{ + struct hwspinlock_device *bank; + struct device_node *syscon; + struct reg_field field; + struct regmap *regmap; + size_t array_size; + u32 stride; + u32 base; + int ret; + int i; + + syscon = of_parse_phandle(pdev->dev.of_node, "syscon", 0); + if (!syscon) { + dev_err(&pdev->dev, "no syscon property\n"); + return -ENODEV; + } + + regmap = syscon_node_to_regmap(syscon); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + ret = of_property_read_u32_index(pdev->dev.of_node, "syscon", 1, &base); + if (ret < 0) { + dev_err(&pdev->dev, "no offset in syscon\n"); + return -EINVAL; + } + + ret = of_property_read_u32_index(pdev->dev.of_node, "syscon", 2, &stride); + if (ret < 0) { + dev_err(&pdev->dev, "no stride syscon\n"); + return -EINVAL; + } + + array_size = QCOM_MUTEX_NUM_LOCKS * sizeof(struct hwspinlock); + bank = devm_kzalloc(&pdev->dev, sizeof(*bank) + array_size, GFP_KERNEL); + if (!bank) + return -ENOMEM; + + platform_set_drvdata(pdev, bank); + + for (i = 0; i < QCOM_MUTEX_NUM_LOCKS; i++) { + field.reg = base + i * stride; + field.lsb = 0; + field.msb = 32; + + bank->lock[i].priv = devm_regmap_field_alloc(&pdev->dev, + regmap, field); + } + + pm_runtime_enable(&pdev->dev); + + ret = hwspin_lock_register(bank, &pdev->dev, &qcom_hwspinlock_ops, + 0, QCOM_MUTEX_NUM_LOCKS); + if (ret) + pm_runtime_disable(&pdev->dev); + + return ret; +} + +static int qcom_hwspinlock_remove(struct platform_device *pdev) +{ + struct hwspinlock_device *bank = platform_get_drvdata(pdev); + int ret; + + ret = hwspin_lock_unregister(bank); + if (ret) { + dev_err(&pdev->dev, "%s failed: %d\n", __func__, ret); + return ret; + } + + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static struct platform_driver qcom_hwspinlock_driver = { + .probe = qcom_hwspinlock_probe, + .remove = qcom_hwspinlock_remove, + .driver = { + .name = "qcom_hwspinlock", + .of_match_table = qcom_hwspinlock_of_match, + }, +}; + +static int __init qcom_hwspinlock_init(void) +{ + return platform_driver_register(&qcom_hwspinlock_driver); +} +/* board init code might need to reserve hwspinlocks for predefined purposes */ +postcore_initcall(qcom_hwspinlock_init); + +static void __exit qcom_hwspinlock_exit(void) +{ + platform_driver_unregister(&qcom_hwspinlock_driver); +} +module_exit(qcom_hwspinlock_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Hardware spinlock driver for Qualcomm SoCs"); -- cgit v1.2.3-70-g09d2 From 9aa1cfca255bf3ba83f44b3452d34cc34607b94a Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Fri, 27 Feb 2015 17:18:21 -0600 Subject: remoteproc/ste: add blank lines after declarations Fix couple of checkpatch warnings of the type, "WARNING: Missing a blank line after declarations" Signed-off-by: Suman Anna Signed-off-by: Ohad Ben-Cohen --- drivers/remoteproc/ste_modem_rproc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/remoteproc/ste_modem_rproc.c b/drivers/remoteproc/ste_modem_rproc.c index dd193f35a1ff..53dc17bdd54e 100644 --- a/drivers/remoteproc/ste_modem_rproc.c +++ b/drivers/remoteproc/ste_modem_rproc.c @@ -67,8 +67,7 @@ static int sproc_load_segments(struct rproc *rproc, const struct firmware *fw) static const struct ste_toc_entry *sproc_find_rsc_entry(const void *data) { int i; - const struct ste_toc *toc; - toc = data; + const struct ste_toc *toc = data; /* Search the table for the resource table */ for (i = 0; i < SPROC_MAX_TOC_ENTRIES && @@ -230,6 +229,7 @@ static int sproc_start(struct rproc *rproc) static int sproc_stop(struct rproc *rproc) { struct sproc *sproc = rproc->priv; + sproc_dbg(sproc, "stop ste-modem\n"); return sproc->mdev->ops.power(sproc->mdev, false); -- cgit v1.2.3-70-g09d2 From e17aee37a68b3884114f515df3ee506870f5eea1 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Fri, 27 Feb 2015 17:18:22 -0600 Subject: remoteproc/davinci: fix quoted split string checkpatch warning Fix the following checkpatch warning, WARNING: quoted string split across lines + "\n\t\tName of DSP firmware file in /lib/firmware" + " (if not specified defaults to 'rproc-dsp-fw')"); Signed-off-by: Suman Anna [remove leading whitespace as well] Signed-off-by: Ohad Ben-Cohen --- drivers/remoteproc/da8xx_remoteproc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/remoteproc/da8xx_remoteproc.c b/drivers/remoteproc/da8xx_remoteproc.c index f8d6a0661c14..009e56f67de2 100644 --- a/drivers/remoteproc/da8xx_remoteproc.c +++ b/drivers/remoteproc/da8xx_remoteproc.c @@ -26,8 +26,7 @@ static char *da8xx_fw_name; module_param(da8xx_fw_name, charp, S_IRUGO); MODULE_PARM_DESC(da8xx_fw_name, - "\n\t\tName of DSP firmware file in /lib/firmware" - " (if not specified defaults to 'rproc-dsp-fw')"); + "Name of DSP firmware file in /lib/firmware (if not specified defaults to 'rproc-dsp-fw')"); /* * OMAP-L138 Technical References: -- cgit v1.2.3-70-g09d2 From 172e6ab1caffcd2dd2910b44d88d096f2c6985fa Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Fri, 27 Feb 2015 17:18:23 -0600 Subject: remoteproc: fix various checkpatch warnings Fix all the checkpatch warnings in the core remoteproc code. The fixes cover the following warnings: 1. WARNING: void function return statements are not generally useful 2. WARNING: Possible unnecessary 'out of memory' message 3. WARNING: line over 80 characters 4. WARNING: braces {} are not necessary for single statement blocks 5. WARNING: Unnecessary space before function pointer arguments Signed-off-by: Suman Anna Signed-off-by: Ohad Ben-Cohen --- drivers/remoteproc/remoteproc_core.c | 27 +++++++++------------------ drivers/remoteproc/remoteproc_internal.h | 2 +- 2 files changed, 10 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 11cdb119e4f3..e991512e04ed 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -132,8 +132,6 @@ static void rproc_disable_iommu(struct rproc *rproc) iommu_detach_device(domain, dev); iommu_domain_free(domain); - - return; } /* @@ -411,10 +409,8 @@ static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc, } trace = kzalloc(sizeof(*trace), GFP_KERNEL); - if (!trace) { - dev_err(dev, "kzalloc trace failed\n"); + if (!trace) return -ENOMEM; - } /* set the trace buffer dma properties */ trace->len = rsc->len; @@ -489,10 +485,8 @@ static int rproc_handle_devmem(struct rproc *rproc, struct fw_rsc_devmem *rsc, } mapping = kzalloc(sizeof(*mapping), GFP_KERNEL); - if (!mapping) { - dev_err(dev, "kzalloc mapping failed\n"); + if (!mapping) return -ENOMEM; - } ret = iommu_map(rproc->domain, rsc->da, rsc->pa, rsc->len, rsc->flags); if (ret) { @@ -565,10 +559,8 @@ static int rproc_handle_carveout(struct rproc *rproc, rsc->da, rsc->pa, rsc->len, rsc->flags); carveout = kzalloc(sizeof(*carveout), GFP_KERNEL); - if (!carveout) { - dev_err(dev, "kzalloc carveout failed\n"); + if (!carveout) return -ENOMEM; - } va = dma_alloc_coherent(dev->parent, rsc->len, &dma, GFP_KERNEL); if (!va) { @@ -768,7 +760,8 @@ static void rproc_resource_cleanup(struct rproc *rproc) /* clean up carveout allocations */ list_for_each_entry_safe(entry, tmp, &rproc->carveouts, node) { - dma_free_coherent(dev->parent, entry->len, entry->va, entry->dma); + dma_free_coherent(dev->parent, entry->len, entry->va, + entry->dma); list_del(&entry->node); kfree(entry); } @@ -808,9 +801,8 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw) /* look for the resource table */ table = rproc_find_rsc_table(rproc, fw, &tablesz); - if (!table) { + if (!table) goto clean_up; - } /* Verify that resource table in loaded fw is unchanged */ if (rproc->table_csum != crc32(0, table, tablesz)) { @@ -911,7 +903,8 @@ static void rproc_fw_config_virtio(const struct firmware *fw, void *context) /* count the number of notify-ids */ rproc->max_notifyid = -1; - ret = rproc_handle_resources(rproc, tablesz, rproc_count_vrings_handler); + ret = rproc_handle_resources(rproc, tablesz, + rproc_count_vrings_handler); if (ret) goto out; @@ -1268,10 +1261,8 @@ struct rproc *rproc_alloc(struct device *dev, const char *name, name_len = strlen(name) + strlen(template) - 2 + 1; rproc = kzalloc(sizeof(struct rproc) + len + name_len, GFP_KERNEL); - if (!rproc) { - dev_err(dev, "%s: kzalloc failed\n", __func__); + if (!rproc) return NULL; - } if (!firmware) { p = (char *)rproc + sizeof(struct rproc) + len; diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h index 70701a50ddfa..8041b95cb058 100644 --- a/drivers/remoteproc/remoteproc_internal.h +++ b/drivers/remoteproc/remoteproc_internal.h @@ -35,7 +35,7 @@ struct rproc; * @get_boot_addr: get boot address to entry point specified in firmware */ struct rproc_fw_ops { - struct resource_table *(*find_rsc_table) (struct rproc *rproc, + struct resource_table *(*find_rsc_table)(struct rproc *rproc, const struct firmware *fw, int *tablesz); struct resource_table *(*find_loaded_rsc_table)(struct rproc *rproc, -- cgit v1.2.3-70-g09d2 From 5b83b2234be6733cfe22036c38031b2c890b3db8 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 21 May 2015 15:51:52 -0700 Subject: mmc: omap_hsmmc: Change wake-up interrupt to use generic wakeirq We can now use generic wakeirq handling and remove the custom handling for the wake-up interrupts. Acked-by: Ulf Hansson Signed-off-by: Tony Lindgren --- drivers/mmc/host/omap_hsmmc.c | 49 ++++++------------------------------------- 1 file changed, 6 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 9df2b6801f76..b2b411da297b 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -43,6 +43,7 @@ #include #include #include +#include #include /* OMAP HSMMC Host Controller Registers */ @@ -218,7 +219,6 @@ struct omap_hsmmc_host { unsigned int flags; #define AUTO_CMD23 (1 << 0) /* Auto CMD23 support */ #define HSMMC_SDIO_IRQ_ENABLED (1 << 1) /* SDIO irq enabled */ -#define HSMMC_WAKE_IRQ_ENABLED (1 << 2) struct omap_hsmmc_next next_data; struct omap_hsmmc_platform_data *pdata; @@ -1117,22 +1117,6 @@ static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id) return IRQ_HANDLED; } -static irqreturn_t omap_hsmmc_wake_irq(int irq, void *dev_id) -{ - struct omap_hsmmc_host *host = dev_id; - - /* cirq is level triggered, disable to avoid infinite loop */ - spin_lock(&host->irq_lock); - if (host->flags & HSMMC_WAKE_IRQ_ENABLED) { - disable_irq_nosync(host->wake_irq); - host->flags &= ~HSMMC_WAKE_IRQ_ENABLED; - } - spin_unlock(&host->irq_lock); - pm_request_resume(host->dev); /* no use counter */ - - return IRQ_HANDLED; -} - static void set_sd_bus_power(struct omap_hsmmc_host *host) { unsigned long i; @@ -1665,7 +1649,6 @@ static void omap_hsmmc_enable_sdio_irq(struct mmc_host *mmc, int enable) static int omap_hsmmc_configure_wake_irq(struct omap_hsmmc_host *host) { - struct mmc_host *mmc = host->mmc; int ret; /* @@ -1677,11 +1660,7 @@ static int omap_hsmmc_configure_wake_irq(struct omap_hsmmc_host *host) if (!host->dev->of_node || !host->wake_irq) return -ENODEV; - /* Prevent auto-enabling of IRQ */ - irq_set_status_flags(host->wake_irq, IRQ_NOAUTOEN); - ret = devm_request_irq(host->dev, host->wake_irq, omap_hsmmc_wake_irq, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, - mmc_hostname(mmc), host); + ret = dev_pm_set_dedicated_wake_irq(host->dev, host->wake_irq); if (ret) { dev_err(mmc_dev(host->mmc), "Unable to request wake IRQ\n"); goto err; @@ -1718,7 +1697,7 @@ static int omap_hsmmc_configure_wake_irq(struct omap_hsmmc_host *host) return 0; err_free_irq: - devm_free_irq(host->dev, host->wake_irq, host); + dev_pm_clear_wake_irq(host->dev); err: dev_warn(host->dev, "no SDIO IRQ support, falling back to polling\n"); host->wake_irq = 0; @@ -2007,6 +1986,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev) omap_hsmmc_ops.multi_io_quirk = omap_hsmmc_multi_io_quirk; } + device_init_wakeup(&pdev->dev, true); pm_runtime_enable(host->dev); pm_runtime_get_sync(host->dev); pm_runtime_set_autosuspend_delay(host->dev, MMC_AUTOSUSPEND_DELAY); @@ -2147,6 +2127,7 @@ err_slot_name: if (host->use_reg) omap_hsmmc_reg_put(host); err_irq: + device_init_wakeup(&pdev->dev, false); if (host->tx_chan) dma_release_channel(host->tx_chan); if (host->rx_chan) @@ -2178,6 +2159,7 @@ static int omap_hsmmc_remove(struct platform_device *pdev) pm_runtime_put_sync(host->dev); pm_runtime_disable(host->dev); + device_init_wakeup(&pdev->dev, false); if (host->dbclk) clk_disable_unprepare(host->dbclk); @@ -2204,11 +2186,6 @@ static int omap_hsmmc_suspend(struct device *dev) OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP); } - /* do not wake up due to sdio irq */ - if ((host->mmc->caps & MMC_CAP_SDIO_IRQ) && - !(host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ)) - disable_irq(host->wake_irq); - if (host->dbclk) clk_disable_unprepare(host->dbclk); @@ -2233,11 +2210,6 @@ static int omap_hsmmc_resume(struct device *dev) omap_hsmmc_conf_bus_power(host); omap_hsmmc_protect_card(host); - - if ((host->mmc->caps & MMC_CAP_SDIO_IRQ) && - !(host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ)) - enable_irq(host->wake_irq); - pm_runtime_mark_last_busy(host->dev); pm_runtime_put_autosuspend(host->dev); return 0; @@ -2277,10 +2249,6 @@ static int omap_hsmmc_runtime_suspend(struct device *dev) } pinctrl_pm_select_idle_state(dev); - - WARN_ON(host->flags & HSMMC_WAKE_IRQ_ENABLED); - enable_irq(host->wake_irq); - host->flags |= HSMMC_WAKE_IRQ_ENABLED; } else { pinctrl_pm_select_idle_state(dev); } @@ -2302,11 +2270,6 @@ static int omap_hsmmc_runtime_resume(struct device *dev) spin_lock_irqsave(&host->irq_lock, flags); if ((host->mmc->caps & MMC_CAP_SDIO_IRQ) && (host->flags & HSMMC_SDIO_IRQ_ENABLED)) { - /* sdio irq flag can't change while in runtime suspend */ - if (host->flags & HSMMC_WAKE_IRQ_ENABLED) { - disable_irq_nosync(host->wake_irq); - host->flags &= ~HSMMC_WAKE_IRQ_ENABLED; - } pinctrl_pm_select_default_state(host->dev); -- cgit v1.2.3-70-g09d2 From f75b6fae1a1d0a79dcbb9cbaed1d06bf3fe57a3c Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Sun, 19 Apr 2015 20:27:19 +0300 Subject: target: Merge sbc_verify_dif_read|write Instead of providing DIF verify routines for read/write that are almost identical and conditionally copy protection information, just let the caller do the right thing. Have a single sbc_dif_verify that handles an sgl (that does NOT copy any data) and a protection information copy routine used by rd_mcp and fileio backend. In the WRITE case, call sbc_dif_verify with cmd->t_prot_sg and then do the copy from it to local sgl (assuming the verify succeeded of course). In the READ case, call sbc_dif_verify with the local sgl and if it succeeds, copy it to t_prot_sg (or not if we are stripping it). (Fix apply breakage from commit c836777 - nab) Tested-by: Akinobu Mita Signed-off-by: Sagi Grimberg Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_file.c | 10 ++-- drivers/target/target_core_rd.c | 20 +++++--- drivers/target/target_core_sbc.c | 94 +++------------------------------- drivers/target/target_core_transport.c | 17 +++--- include/target/target_core_backend.h | 8 ++- 5 files changed, 37 insertions(+), 112 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index 3f27bfd816d8..deec7560f835 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -643,13 +643,14 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, if (ret > 0 && cmd->prot_type && dev->dev_attrib.pi_prot_type) { u32 sectors = cmd->data_length / dev->dev_attrib.block_size; - rc = sbc_dif_verify_read(cmd, cmd->t_task_lba, sectors, - 0, fd_prot.prot_sg, 0); + rc = sbc_dif_verify(cmd, cmd->t_task_lba, sectors, + 0, fd_prot.prot_sg, 0); if (rc) { kfree(fd_prot.prot_sg); kfree(fd_prot.prot_buf); return rc; } + sbc_dif_copy_prot(cmd, sectors, true, fd_prot.prot_sg, 0); kfree(fd_prot.prot_sg); kfree(fd_prot.prot_buf); } @@ -663,13 +664,14 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, if (ret < 0) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - rc = sbc_dif_verify_write(cmd, cmd->t_task_lba, sectors, - 0, fd_prot.prot_sg, 0); + rc = sbc_dif_verify(cmd, cmd->t_task_lba, sectors, + 0, cmd->t_prot_sg, 0); if (rc) { kfree(fd_prot.prot_sg); kfree(fd_prot.prot_buf); return rc; } + sbc_dif_copy_prot(cmd, sectors, false, fd_prot.prot_sg, 0); } ret = fd_do_rw(cmd, sgl, sgl_nents, 1); diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c index d16489b6a1a4..55315fd0f5d3 100644 --- a/drivers/target/target_core_rd.c +++ b/drivers/target/target_core_rd.c @@ -403,10 +403,7 @@ static struct rd_dev_sg_table *rd_get_prot_table(struct rd_dev *rd_dev, u32 page return NULL; } -typedef sense_reason_t (*dif_verify)(struct se_cmd *, sector_t, unsigned int, - unsigned int, struct scatterlist *, int); - -static sense_reason_t rd_do_prot_rw(struct se_cmd *cmd, dif_verify dif_verify) +static sense_reason_t rd_do_prot_rw(struct se_cmd *cmd, bool is_read) { struct se_device *se_dev = cmd->se_dev; struct rd_dev *dev = RD_DEV(se_dev); @@ -466,7 +463,16 @@ static sense_reason_t rd_do_prot_rw(struct se_cmd *cmd, dif_verify dif_verify) #endif /* !CONFIG_ARCH_HAS_SG_CHAIN */ - rc = dif_verify(cmd, cmd->t_task_lba, sectors, 0, prot_sg, prot_offset); + if (is_read) + rc = sbc_dif_verify(cmd, cmd->t_task_lba, sectors, 0, + prot_sg, prot_offset); + else + rc = sbc_dif_verify(cmd, cmd->t_task_lba, sectors, 0, + cmd->t_prot_sg, 0); + + if (!rc) + sbc_dif_copy_prot(cmd, sectors, is_read, prot_sg, prot_offset); + if (need_to_release) kfree(prot_sg); @@ -512,7 +518,7 @@ rd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, if (cmd->prot_type && se_dev->dev_attrib.pi_prot_type && data_direction == DMA_TO_DEVICE) { - rc = rd_do_prot_rw(cmd, sbc_dif_verify_write); + rc = rd_do_prot_rw(cmd, false); if (rc) return rc; } @@ -580,7 +586,7 @@ rd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, if (cmd->prot_type && se_dev->dev_attrib.pi_prot_type && data_direction == DMA_FROM_DEVICE) { - rc = rd_do_prot_rw(cmd, sbc_dif_verify_read); + rc = rd_do_prot_rw(cmd, true); if (rc) return rc; } diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 733824e3825f..ca95fab3521a 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -1266,9 +1266,8 @@ check_ref: return 0; } -static void -sbc_dif_copy_prot(struct se_cmd *cmd, unsigned int sectors, bool read, - struct scatterlist *sg, int sg_off) +void sbc_dif_copy_prot(struct se_cmd *cmd, unsigned int sectors, bool read, + struct scatterlist *sg, int sg_off) { struct se_device *dev = cmd->se_dev; struct scatterlist *psg; @@ -1309,68 +1308,11 @@ sbc_dif_copy_prot(struct se_cmd *cmd, unsigned int sectors, bool read, kunmap_atomic(paddr); } } +EXPORT_SYMBOL(sbc_dif_copy_prot); sense_reason_t -sbc_dif_verify_write(struct se_cmd *cmd, sector_t start, unsigned int sectors, - unsigned int ei_lba, struct scatterlist *sg, int sg_off) -{ - struct se_device *dev = cmd->se_dev; - struct se_dif_v1_tuple *sdt; - struct scatterlist *dsg, *psg = cmd->t_prot_sg; - sector_t sector = start; - void *daddr, *paddr; - int i, j, offset = 0; - sense_reason_t rc; - - for_each_sg(cmd->t_data_sg, dsg, cmd->t_data_nents, i) { - daddr = kmap_atomic(sg_page(dsg)) + dsg->offset; - paddr = kmap_atomic(sg_page(psg)) + psg->offset; - - for (j = 0; j < dsg->length; j += dev->dev_attrib.block_size) { - - if (offset >= psg->length) { - kunmap_atomic(paddr); - psg = sg_next(psg); - paddr = kmap_atomic(sg_page(psg)) + psg->offset; - offset = 0; - } - - sdt = paddr + offset; - - pr_debug("DIF WRITE sector: %llu guard_tag: 0x%04x" - " app_tag: 0x%04x ref_tag: %u\n", - (unsigned long long)sector, sdt->guard_tag, - sdt->app_tag, be32_to_cpu(sdt->ref_tag)); - - rc = sbc_dif_v1_verify(cmd, sdt, daddr + j, sector, - ei_lba); - if (rc) { - kunmap_atomic(paddr); - kunmap_atomic(daddr); - cmd->bad_sector = sector; - return rc; - } - - sector++; - ei_lba++; - offset += sizeof(struct se_dif_v1_tuple); - } - - kunmap_atomic(paddr); - kunmap_atomic(daddr); - } - if (!sg) - return 0; - - sbc_dif_copy_prot(cmd, sectors, false, sg, sg_off); - - return 0; -} -EXPORT_SYMBOL(sbc_dif_verify_write); - -static sense_reason_t -__sbc_dif_verify_read(struct se_cmd *cmd, sector_t start, unsigned int sectors, - unsigned int ei_lba, struct scatterlist *sg, int sg_off) +sbc_dif_verify(struct se_cmd *cmd, sector_t start, unsigned int sectors, + unsigned int ei_lba, struct scatterlist *sg, int sg_off) { struct se_device *dev = cmd->se_dev; struct se_dif_v1_tuple *sdt; @@ -1426,28 +1368,4 @@ __sbc_dif_verify_read(struct se_cmd *cmd, sector_t start, unsigned int sectors, return 0; } - -sense_reason_t -sbc_dif_read_strip(struct se_cmd *cmd) -{ - struct se_device *dev = cmd->se_dev; - u32 sectors = cmd->prot_length / dev->prot_length; - - return __sbc_dif_verify_read(cmd, cmd->t_task_lba, sectors, 0, - cmd->t_prot_sg, 0); -} - -sense_reason_t -sbc_dif_verify_read(struct se_cmd *cmd, sector_t start, unsigned int sectors, - unsigned int ei_lba, struct scatterlist *sg, int sg_off) -{ - sense_reason_t rc; - - rc = __sbc_dif_verify_read(cmd, start, sectors, ei_lba, sg, sg_off); - if (rc) - return rc; - - sbc_dif_copy_prot(cmd, sectors, true, sg, sg_off); - return 0; -} -EXPORT_SYMBOL(sbc_dif_verify_read); +EXPORT_SYMBOL(sbc_dif_verify); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 675f2d9d1f14..105f4fd0fad4 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1766,8 +1766,8 @@ static int target_write_prot_action(struct se_cmd *cmd) break; sectors = cmd->data_length >> ilog2(cmd->se_dev->dev_attrib.block_size); - cmd->pi_err = sbc_dif_verify_write(cmd, cmd->t_task_lba, - sectors, 0, NULL, 0); + cmd->pi_err = sbc_dif_verify(cmd, cmd->t_task_lba, + sectors, 0, cmd->t_prot_sg, 0); if (unlikely(cmd->pi_err)) { spin_lock_irq(&cmd->t_state_lock); cmd->transport_state &= ~(CMD_T_BUSY|CMD_T_SENT); @@ -1991,16 +1991,17 @@ static void transport_handle_queue_full( static bool target_read_prot_action(struct se_cmd *cmd) { - sense_reason_t rc; - switch (cmd->prot_op) { case TARGET_PROT_DIN_STRIP: if (!(cmd->se_sess->sup_prot_ops & TARGET_PROT_DIN_STRIP)) { - rc = sbc_dif_read_strip(cmd); - if (rc) { - cmd->pi_err = rc; + u32 sectors = cmd->data_length >> + ilog2(cmd->se_dev->dev_attrib.block_size); + + cmd->pi_err = sbc_dif_verify(cmd, cmd->t_task_lba, + sectors, 0, cmd->t_prot_sg, + 0); + if (cmd->pi_err) return true; - } } break; case TARGET_PROT_DIN_INSERT: diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index 5f1225706993..47fafec556f8 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -84,12 +84,10 @@ sense_reason_t sbc_execute_unmap(struct se_cmd *cmd, sector_t lba, sector_t nolb), void *priv); void sbc_dif_generate(struct se_cmd *); -sense_reason_t sbc_dif_verify_write(struct se_cmd *, sector_t, unsigned int, +sense_reason_t sbc_dif_verify(struct se_cmd *, sector_t, unsigned int, unsigned int, struct scatterlist *, int); -sense_reason_t sbc_dif_verify_read(struct se_cmd *, sector_t, unsigned int, - unsigned int, struct scatterlist *, int); -sense_reason_t sbc_dif_read_strip(struct se_cmd *); - +void sbc_dif_copy_prot(struct se_cmd *, unsigned int, bool, + struct scatterlist *, int); void transport_set_vpd_proto_id(struct t10_vpd *, unsigned char *); int transport_set_vpd_assoc(struct t10_vpd *, unsigned char *); int transport_set_vpd_ident_type(struct t10_vpd *, unsigned char *); -- cgit v1.2.3-70-g09d2 From 8287fa5fb43c3fa05748560b8e13b91c4e88f586 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Sun, 19 Apr 2015 20:27:20 +0300 Subject: target/file: Remove fd_prot bounce buffer The reason this bounce buffer exists is to allow code reuse between rd_mcp and fileio in DIF mode. But the fact is, that this bounce is really not needed at all, we can simply call sbc_dif_verify on cmd->t_prot_sg and use it for file IO. This also removes fd_do_prot_rw as fd_do_rw was generalised to receive file pointer, block size (8 bytes for DIF data) and total data length. (Fix apply breakage from commit c836777 - nab) Tested-by: Akinobu Mita Signed-off-by: Sagi Grimberg Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_file.c | 128 +++++++++----------------------------- drivers/target/target_core_file.h | 6 -- 2 files changed, 28 insertions(+), 106 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index deec7560f835..fe6c19c1e001 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -258,75 +258,15 @@ static void fd_free_device(struct se_device *dev) kfree(fd_dev); } -static int fd_do_prot_rw(struct se_cmd *cmd, struct fd_prot *fd_prot, - int is_write) +static int fd_do_rw(struct se_cmd *cmd, struct file *fd, + u32 block_size, struct scatterlist *sgl, + u32 sgl_nents, u32 data_length, int is_write) { - struct se_device *se_dev = cmd->se_dev; - struct fd_dev *dev = FD_DEV(se_dev); - struct file *prot_fd = dev->fd_prot_file; - loff_t pos = (cmd->t_task_lba * se_dev->prot_length); - unsigned char *buf; - u32 prot_size; - int rc, ret = 1; - - prot_size = (cmd->data_length / se_dev->dev_attrib.block_size) * - se_dev->prot_length; - - if (!is_write) { - fd_prot->prot_buf = kzalloc(prot_size, GFP_KERNEL); - if (!fd_prot->prot_buf) { - pr_err("Unable to allocate fd_prot->prot_buf\n"); - return -ENOMEM; - } - buf = fd_prot->prot_buf; - - fd_prot->prot_sg_nents = 1; - fd_prot->prot_sg = kzalloc(sizeof(struct scatterlist), - GFP_KERNEL); - if (!fd_prot->prot_sg) { - pr_err("Unable to allocate fd_prot->prot_sg\n"); - kfree(fd_prot->prot_buf); - return -ENOMEM; - } - sg_init_table(fd_prot->prot_sg, fd_prot->prot_sg_nents); - sg_set_buf(fd_prot->prot_sg, buf, prot_size); - } - - if (is_write) { - rc = kernel_write(prot_fd, fd_prot->prot_buf, prot_size, pos); - if (rc < 0 || prot_size != rc) { - pr_err("kernel_write() for fd_do_prot_rw failed:" - " %d\n", rc); - ret = -EINVAL; - } - } else { - rc = kernel_read(prot_fd, pos, fd_prot->prot_buf, prot_size); - if (rc < 0) { - pr_err("kernel_read() for fd_do_prot_rw failed:" - " %d\n", rc); - ret = -EINVAL; - } - } - - if (is_write || ret < 0) { - kfree(fd_prot->prot_sg); - kfree(fd_prot->prot_buf); - } - - return ret; -} - -static int fd_do_rw(struct se_cmd *cmd, struct scatterlist *sgl, - u32 sgl_nents, int is_write) -{ - struct se_device *se_dev = cmd->se_dev; - struct fd_dev *dev = FD_DEV(se_dev); - struct file *fd = dev->fd_file; struct scatterlist *sg; struct iov_iter iter; struct bio_vec *bvec; ssize_t len = 0; - loff_t pos = (cmd->t_task_lba * se_dev->dev_attrib.block_size); + loff_t pos = (cmd->t_task_lba * block_size); int ret = 0, i; bvec = kcalloc(sgl_nents, sizeof(struct bio_vec), GFP_KERNEL); @@ -352,7 +292,7 @@ static int fd_do_rw(struct se_cmd *cmd, struct scatterlist *sgl, kfree(bvec); if (is_write) { - if (ret < 0 || ret != cmd->data_length) { + if (ret < 0 || ret != data_length) { pr_err("%s() write returned %d\n", __func__, ret); return (ret < 0 ? ret : -EINVAL); } @@ -363,10 +303,10 @@ static int fd_do_rw(struct se_cmd *cmd, struct scatterlist *sgl, * block_device. */ if (S_ISBLK(file_inode(fd)->i_mode)) { - if (ret < 0 || ret != cmd->data_length) { + if (ret < 0 || ret != data_length) { pr_err("%s() returned %d, expecting %u for " "S_ISBLK\n", __func__, ret, - cmd->data_length); + data_length); return (ret < 0 ? ret : -EINVAL); } } else { @@ -612,7 +552,9 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, enum dma_data_direction data_direction) { struct se_device *dev = cmd->se_dev; - struct fd_prot fd_prot; + struct fd_dev *fd_dev = FD_DEV(dev); + struct file *file = fd_dev->fd_file; + struct file *pfile = fd_dev->fd_prot_file; sense_reason_t rc; int ret = 0; /* @@ -630,51 +572,39 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, * physical memory addresses to struct iovec virtual memory. */ if (data_direction == DMA_FROM_DEVICE) { - memset(&fd_prot, 0, sizeof(struct fd_prot)); - if (cmd->prot_type && dev->dev_attrib.pi_prot_type) { - ret = fd_do_prot_rw(cmd, &fd_prot, false); + ret = fd_do_rw(cmd, pfile, dev->prot_length, + cmd->t_prot_sg, cmd->t_prot_nents, + cmd->prot_length, 0); if (ret < 0) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } - ret = fd_do_rw(cmd, sgl, sgl_nents, 0); + ret = fd_do_rw(cmd, file, dev->dev_attrib.block_size, + sgl, sgl_nents, cmd->data_length, 0); if (ret > 0 && cmd->prot_type && dev->dev_attrib.pi_prot_type) { - u32 sectors = cmd->data_length / dev->dev_attrib.block_size; + u32 sectors = cmd->data_length >> + ilog2(dev->dev_attrib.block_size); rc = sbc_dif_verify(cmd, cmd->t_task_lba, sectors, - 0, fd_prot.prot_sg, 0); - if (rc) { - kfree(fd_prot.prot_sg); - kfree(fd_prot.prot_buf); + 0, cmd->t_prot_sg, 0); + if (rc) return rc; - } - sbc_dif_copy_prot(cmd, sectors, true, fd_prot.prot_sg, 0); - kfree(fd_prot.prot_sg); - kfree(fd_prot.prot_buf); } } else { - memset(&fd_prot, 0, sizeof(struct fd_prot)); - if (cmd->prot_type && dev->dev_attrib.pi_prot_type) { - u32 sectors = cmd->data_length / dev->dev_attrib.block_size; - - ret = fd_do_prot_rw(cmd, &fd_prot, false); - if (ret < 0) - return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + u32 sectors = cmd->data_length >> + ilog2(dev->dev_attrib.block_size); rc = sbc_dif_verify(cmd, cmd->t_task_lba, sectors, 0, cmd->t_prot_sg, 0); - if (rc) { - kfree(fd_prot.prot_sg); - kfree(fd_prot.prot_buf); + if (rc) return rc; - } - sbc_dif_copy_prot(cmd, sectors, false, fd_prot.prot_sg, 0); } - ret = fd_do_rw(cmd, sgl, sgl_nents, 1); + ret = fd_do_rw(cmd, file, dev->dev_attrib.block_size, + sgl, sgl_nents, cmd->data_length, 1); /* * Perform implicit vfs_fsync_range() for fd_do_writev() ops * for SCSI WRITEs with Forced Unit Access (FUA) set. @@ -683,7 +613,6 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, if (ret > 0 && dev->dev_attrib.emulate_fua_write > 0 && (cmd->se_cmd_flags & SCF_FUA)) { - struct fd_dev *fd_dev = FD_DEV(dev); loff_t start = cmd->t_task_lba * dev->dev_attrib.block_size; loff_t end; @@ -697,17 +626,16 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, } if (ret > 0 && cmd->prot_type && dev->dev_attrib.pi_prot_type) { - ret = fd_do_prot_rw(cmd, &fd_prot, true); + ret = fd_do_rw(cmd, pfile, dev->prot_length, + cmd->t_prot_sg, cmd->t_prot_nents, + cmd->prot_length, 1); if (ret < 0) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } } - if (ret < 0) { - kfree(fd_prot.prot_sg); - kfree(fd_prot.prot_buf); + if (ret < 0) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - } if (ret) target_complete_cmd(cmd, SAM_STAT_GOOD); diff --git a/drivers/target/target_core_file.h b/drivers/target/target_core_file.h index 182cbb295039..068966fce308 100644 --- a/drivers/target/target_core_file.h +++ b/drivers/target/target_core_file.h @@ -21,12 +21,6 @@ #define FDBD_HAS_BUFFERED_IO_WCE 0x04 #define FDBD_FORMAT_UNIT_SIZE 2048 -struct fd_prot { - unsigned char *prot_buf; - struct scatterlist *prot_sg; - u32 prot_sg_nents; -}; - struct fd_dev { struct se_device dev; -- cgit v1.2.3-70-g09d2 From 414e4627277e38e3a557c53c9def7fe9f1ec9b2c Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Sun, 19 Apr 2015 20:27:21 +0300 Subject: target/sbc: Fix sbc_dif_verify inconsistent map/unmap Fix map/unmap consistency and get rid of a redundant local variable psg. Reported-by: Akinobu Mita Signed-off-by: Sagi Grimberg Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_sbc.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index ca95fab3521a..3df2cd538478 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -1312,30 +1312,30 @@ EXPORT_SYMBOL(sbc_dif_copy_prot); sense_reason_t sbc_dif_verify(struct se_cmd *cmd, sector_t start, unsigned int sectors, - unsigned int ei_lba, struct scatterlist *sg, int sg_off) + unsigned int ei_lba, struct scatterlist *psg, int psg_off) { struct se_device *dev = cmd->se_dev; struct se_dif_v1_tuple *sdt; - struct scatterlist *dsg, *psg = sg; + struct scatterlist *dsg; sector_t sector = start; void *daddr, *paddr; - int i, j, offset = sg_off; + int i, j; sense_reason_t rc; for_each_sg(cmd->t_data_sg, dsg, cmd->t_data_nents, i) { daddr = kmap_atomic(sg_page(dsg)) + dsg->offset; - paddr = kmap_atomic(sg_page(psg)) + sg->offset; + paddr = kmap_atomic(sg_page(psg)) + psg->offset; for (j = 0; j < dsg->length; j += dev->dev_attrib.block_size) { - if (offset >= psg->length) { - kunmap_atomic(paddr); + if (psg_off >= psg->length) { + kunmap_atomic(paddr - psg->offset); psg = sg_next(psg); paddr = kmap_atomic(sg_page(psg)) + psg->offset; - offset = 0; + psg_off = 0; } - sdt = paddr + offset; + sdt = paddr + psg_off; pr_debug("DIF READ sector: %llu guard_tag: 0x%04x" " app_tag: 0x%04x ref_tag: %u\n", @@ -1344,26 +1344,26 @@ sbc_dif_verify(struct se_cmd *cmd, sector_t start, unsigned int sectors, if (sdt->app_tag == cpu_to_be16(0xffff)) { sector++; - offset += sizeof(struct se_dif_v1_tuple); + psg_off += sizeof(struct se_dif_v1_tuple); continue; } rc = sbc_dif_v1_verify(cmd, sdt, daddr + j, sector, ei_lba); if (rc) { - kunmap_atomic(paddr); - kunmap_atomic(daddr); + kunmap_atomic(paddr - psg->offset); + kunmap_atomic(daddr - dsg->offset); cmd->bad_sector = sector; return rc; } sector++; ei_lba++; - offset += sizeof(struct se_dif_v1_tuple); + psg_off += sizeof(struct se_dif_v1_tuple); } - kunmap_atomic(paddr); - kunmap_atomic(daddr); + kunmap_atomic(paddr - psg->offset); + kunmap_atomic(daddr - dsg->offset); } return 0; -- cgit v1.2.3-70-g09d2 From c04a6091c951c88636a569cdd29feb65fb5003af Mon Sep 17 00:00:00 2001 From: Christophe Vu-Brugier Date: Sun, 19 Apr 2015 22:18:33 +0200 Subject: iscsi-target: remove support for obsolete markers Support for markers is currently broken because of a bug in iscsi_enforce_integrity_rules(): the "IFMarkInt_Reject" and "OFMarkInt_Reject" variables are always equal to 1 in iscsi_enforce_integrity_rules(). Moreover, fixed interval markers keys (IFMarker, OFMarker, IFMarkInt and OFMarkInt) are obsolete according to iSCSI RFC 7143: >From http://tools.ietf.org/html/rfc7143#section-13.25: 13.25. Obsoleted Keys This document obsoletes the following keys defined in [RFC3720]: IFMarker, OFMarker, OFMarkInt, and IFMarkInt. However, iSCSI implementations compliant to this document may still receive these obsoleted keys -- i.e., in a responder role -- in a text negotiation. When an IFMarker or OFMarker key is received, a compliant iSCSI implementation SHOULD respond with the constant "Reject" value. The implementation MAY alternatively respond with a "No" value. However, the implementation MUST NOT respond with a "NotUnderstood" value for either of these keys. When an IFMarkInt or OFMarkInt key is received, a compliant iSCSI implementation MUST respond with the constant "Reject" value. The implementation MUST NOT respond with a "NotUnderstood" value for either of these keys. This patch disables markers by turning the corresponding parameters to read-only. The default value of IFMarker and OFMarker remains "No" but the user cannot change it to "Yes" anymore. The new value of IFMarkInt and OFMarkInt is "Reject". (Drop left-over iscsi_get_value_from_number_range + make configfs parameters attrs R/W nops - nab) Signed-off-by: Christophe Vu-Brugier Signed-off-by: Nicholas Bellinger --- drivers/target/iscsi/iscsi_target.c | 20 +- drivers/target/iscsi/iscsi_target_erl0.c | 53 ----- drivers/target/iscsi/iscsi_target_erl0.h | 1 - drivers/target/iscsi/iscsi_target_login.c | 58 +----- drivers/target/iscsi/iscsi_target_login.h | 1 - drivers/target/iscsi/iscsi_target_parameters.c | 267 +------------------------ drivers/target/iscsi/iscsi_target_parameters.h | 11 +- drivers/target/iscsi/iscsi_target_util.c | 48 ----- drivers/target/iscsi/iscsi_target_util.h | 1 - include/target/iscsi/iscsi_target_core.h | 10 - 10 files changed, 16 insertions(+), 454 deletions(-) (limited to 'drivers') diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 74e6114ff18f..21620c751071 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -2736,11 +2736,7 @@ static int iscsit_send_datain(struct iscsi_cmd *cmd, struct iscsi_conn *conn) cmd->iov_data_count = iov_count; cmd->tx_size = tx_size; - /* sendpage is preferred but can't insert markers */ - if (!conn->conn_ops->IFMarker) - ret = iscsit_fe_sendpage_sg(cmd, conn); - else - ret = iscsit_send_tx_data(cmd, conn, 0); + ret = iscsit_fe_sendpage_sg(cmd, conn); iscsit_unmap_iovec(cmd); @@ -4072,17 +4068,9 @@ static int iscsi_target_rx_opcode(struct iscsi_conn *conn, unsigned char *buf) " opcode while ERL=0, closing iSCSI connection.\n"); return -1; } - if (!conn->conn_ops->OFMarker) { - pr_err("Unable to recover from unknown" - " opcode while OFMarker=No, closing iSCSI" - " connection.\n"); - return -1; - } - if (iscsit_recover_from_unknown_opcode(conn) < 0) { - pr_err("Unable to recover from unknown" - " opcode, closing iSCSI connection.\n"); - return -1; - } + pr_err("Unable to recover from unknown opcode while OFMarker=No," + " closing iSCSI connection.\n"); + ret = -1; break; } diff --git a/drivers/target/iscsi/iscsi_target_erl0.c b/drivers/target/iscsi/iscsi_target_erl0.c index 959a14c9dd5d..210f6e4830e3 100644 --- a/drivers/target/iscsi/iscsi_target_erl0.c +++ b/drivers/target/iscsi/iscsi_target_erl0.c @@ -956,56 +956,3 @@ void iscsit_take_action_for_connection_exit(struct iscsi_conn *conn) iscsit_handle_connection_cleanup(conn); } - -/* - * This is the simple function that makes the magic of - * sync and steering happen in the follow paradoxical order: - * - * 0) Receive conn->of_marker (bytes left until next OFMarker) - * bytes into an offload buffer. When we pass the exact number - * of bytes in conn->of_marker, iscsit_dump_data_payload() and hence - * rx_data() will automatically receive the identical u32 marker - * values and store it in conn->of_marker_offset; - * 1) Now conn->of_marker_offset will contain the offset to the start - * of the next iSCSI PDU. Dump these remaining bytes into another - * offload buffer. - * 2) We are done! - * Next byte in the TCP stream will contain the next iSCSI PDU! - * Cool Huh?! - */ -int iscsit_recover_from_unknown_opcode(struct iscsi_conn *conn) -{ - /* - * Make sure the remaining bytes to next maker is a sane value. - */ - if (conn->of_marker > (conn->conn_ops->OFMarkInt * 4)) { - pr_err("Remaining bytes to OFMarker: %u exceeds" - " OFMarkInt bytes: %u.\n", conn->of_marker, - conn->conn_ops->OFMarkInt * 4); - return -1; - } - - pr_debug("Advancing %u bytes in TCP stream to get to the" - " next OFMarker.\n", conn->of_marker); - - if (iscsit_dump_data_payload(conn, conn->of_marker, 0) < 0) - return -1; - - /* - * Make sure the offset marker we retrived is a valid value. - */ - if (conn->of_marker_offset > (ISCSI_HDR_LEN + (ISCSI_CRC_LEN * 2) + - conn->conn_ops->MaxRecvDataSegmentLength)) { - pr_err("OfMarker offset value: %u exceeds limit.\n", - conn->of_marker_offset); - return -1; - } - - pr_debug("Discarding %u bytes of TCP stream to get to the" - " next iSCSI Opcode.\n", conn->of_marker_offset); - - if (iscsit_dump_data_payload(conn, conn->of_marker_offset, 0) < 0) - return -1; - - return 0; -} diff --git a/drivers/target/iscsi/iscsi_target_erl0.h b/drivers/target/iscsi/iscsi_target_erl0.h index 21acc9a06376..a9e2f9497fb2 100644 --- a/drivers/target/iscsi/iscsi_target_erl0.h +++ b/drivers/target/iscsi/iscsi_target_erl0.h @@ -10,6 +10,5 @@ extern void iscsit_connection_reinstatement_rcfr(struct iscsi_conn *); extern void iscsit_cause_connection_reinstatement(struct iscsi_conn *, int); extern void iscsit_fall_back_to_erl0(struct iscsi_session *); extern void iscsit_take_action_for_connection_exit(struct iscsi_conn *); -extern int iscsit_recover_from_unknown_opcode(struct iscsi_conn *); #endif /*** ISCSI_TARGET_ERL0_H ***/ diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index 70d799dfab03..3d0fe4ff5590 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -410,8 +410,6 @@ static int iscsi_login_zero_tsih_s2( if (iscsi_change_param_sprintf(conn, "ErrorRecoveryLevel=%d", na->default_erl)) return -1; - if (iscsi_login_disable_FIM_keys(conn->param_list, conn) < 0) - return -1; /* * Set RDMAExtensions=Yes by default for iSER enabled network portals */ @@ -477,59 +475,6 @@ check_prot: return 0; } -/* - * Remove PSTATE_NEGOTIATE for the four FIM related keys. - * The Initiator node will be able to enable FIM by proposing them itself. - */ -int iscsi_login_disable_FIM_keys( - struct iscsi_param_list *param_list, - struct iscsi_conn *conn) -{ - struct iscsi_param *param; - - param = iscsi_find_param_from_key("OFMarker", param_list); - if (!param) { - pr_err("iscsi_find_param_from_key() for" - " OFMarker failed\n"); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, - ISCSI_LOGIN_STATUS_NO_RESOURCES); - return -1; - } - param->state &= ~PSTATE_NEGOTIATE; - - param = iscsi_find_param_from_key("OFMarkInt", param_list); - if (!param) { - pr_err("iscsi_find_param_from_key() for" - " IFMarker failed\n"); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, - ISCSI_LOGIN_STATUS_NO_RESOURCES); - return -1; - } - param->state &= ~PSTATE_NEGOTIATE; - - param = iscsi_find_param_from_key("IFMarker", param_list); - if (!param) { - pr_err("iscsi_find_param_from_key() for" - " IFMarker failed\n"); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, - ISCSI_LOGIN_STATUS_NO_RESOURCES); - return -1; - } - param->state &= ~PSTATE_NEGOTIATE; - - param = iscsi_find_param_from_key("IFMarkInt", param_list); - if (!param) { - pr_err("iscsi_find_param_from_key() for" - " IFMarker failed\n"); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, - ISCSI_LOGIN_STATUS_NO_RESOURCES); - return -1; - } - param->state &= ~PSTATE_NEGOTIATE; - - return 0; -} - static int iscsi_login_non_zero_tsih_s1( struct iscsi_conn *conn, unsigned char *buf) @@ -616,7 +561,7 @@ static int iscsi_login_non_zero_tsih_s2( if (iscsi_change_param_sprintf(conn, "TargetPortalGroupTag=%hu", sess->tpg->tpgt)) return -1; - return iscsi_login_disable_FIM_keys(conn->param_list, conn); + return 0; } int iscsi_login_post_auth_non_zero_tsih( @@ -765,7 +710,6 @@ int iscsi_post_login_handler( conn->conn_state = TARG_CONN_STATE_LOGGED_IN; iscsi_set_connection_parameters(conn->conn_ops, conn->param_list); - iscsit_set_sync_and_steering_values(conn); /* * SCSI Initiator -> SCSI Target Port Mapping */ diff --git a/drivers/target/iscsi/iscsi_target_login.h b/drivers/target/iscsi/iscsi_target_login.h index 29d098324b7f..1c7358081533 100644 --- a/drivers/target/iscsi/iscsi_target_login.h +++ b/drivers/target/iscsi/iscsi_target_login.h @@ -16,6 +16,5 @@ extern int iscsi_post_login_handler(struct iscsi_np *, struct iscsi_conn *, u8); extern void iscsi_target_login_sess_out(struct iscsi_conn *, struct iscsi_np *, bool, bool); extern int iscsi_target_login_thread(void *); -extern int iscsi_login_disable_FIM_keys(struct iscsi_param_list *, struct iscsi_conn *); #endif /*** ISCSI_TARGET_LOGIN_H ***/ diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c index d4f9e9645697..be336df0a887 100644 --- a/drivers/target/iscsi/iscsi_target_parameters.c +++ b/drivers/target/iscsi/iscsi_target_parameters.c @@ -34,13 +34,6 @@ int iscsi_login_rx_data( iov.iov_len = length; iov.iov_base = buf; - /* - * Initial Marker-less Interval. - * Add the values regardless of IFMarker/OFMarker, considering - * it may not be negoitated yet. - */ - conn->of_marker += length; - rx_got = rx_data(conn, &iov, 1, length); if (rx_got != length) { pr_err("rx_data returned %d, expecting %d.\n", @@ -72,13 +65,6 @@ int iscsi_login_tx_data( iov_cnt++; } - /* - * Initial Marker-less Interval. - * Add the values regardless of IFMarker/OFMarker, considering - * it may not be negoitated yet. - */ - conn->if_marker += length; - tx_sent = tx_data(conn, &iov[0], iov_cnt, length); if (tx_sent != length) { pr_err("tx_data returned %d, expecting %d.\n", @@ -97,12 +83,6 @@ void iscsi_dump_conn_ops(struct iscsi_conn_ops *conn_ops) "CRC32C" : "None"); pr_debug("MaxRecvDataSegmentLength: %u\n", conn_ops->MaxRecvDataSegmentLength); - pr_debug("OFMarker: %s\n", (conn_ops->OFMarker) ? "Yes" : "No"); - pr_debug("IFMarker: %s\n", (conn_ops->IFMarker) ? "Yes" : "No"); - if (conn_ops->OFMarker) - pr_debug("OFMarkInt: %u\n", conn_ops->OFMarkInt); - if (conn_ops->IFMarker) - pr_debug("IFMarkInt: %u\n", conn_ops->IFMarkInt); } void iscsi_dump_sess_ops(struct iscsi_sess_ops *sess_ops) @@ -194,10 +174,6 @@ static struct iscsi_param *iscsi_set_default_param(struct iscsi_param_list *para case TYPERANGE_DIGEST: param->type = TYPE_VALUE_LIST | TYPE_STRING; break; - case TYPERANGE_MARKINT: - param->type = TYPE_NUMBER_RANGE; - param->type_range |= TYPERANGE_1_TO_65535; - break; case TYPERANGE_ISCSINAME: case TYPERANGE_SESSIONTYPE: case TYPERANGE_TARGETADDRESS: @@ -422,13 +398,13 @@ int iscsi_create_default_params(struct iscsi_param_list **param_list_ptr) param = iscsi_set_default_param(pl, IFMARKINT, INITIAL_IFMARKINT, PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH, - TYPERANGE_MARKINT, USE_INITIAL_ONLY); + TYPERANGE_UTF8, USE_INITIAL_ONLY); if (!param) goto out; param = iscsi_set_default_param(pl, OFMARKINT, INITIAL_OFMARKINT, PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH, - TYPERANGE_MARKINT, USE_INITIAL_ONLY); + TYPERANGE_UTF8, USE_INITIAL_ONLY); if (!param) goto out; /* @@ -524,9 +500,9 @@ int iscsi_set_keys_to_negotiate( } else if (!strcmp(param->name, OFMARKER)) { SET_PSTATE_NEGOTIATE(param); } else if (!strcmp(param->name, IFMARKINT)) { - SET_PSTATE_NEGOTIATE(param); + SET_PSTATE_REJECT(param); } else if (!strcmp(param->name, OFMARKINT)) { - SET_PSTATE_NEGOTIATE(param); + SET_PSTATE_REJECT(param); } else if (!strcmp(param->name, RDMAEXTENSIONS)) { if (iser) SET_PSTATE_NEGOTIATE(param); @@ -906,91 +882,6 @@ static int iscsi_check_numerical_value(struct iscsi_param *param, char *value_pt return 0; } -static int iscsi_check_numerical_range_value(struct iscsi_param *param, char *value) -{ - char *left_val_ptr = NULL, *right_val_ptr = NULL; - char *tilde_ptr = NULL; - u32 left_val, right_val, local_left_val; - - if (strcmp(param->name, IFMARKINT) && - strcmp(param->name, OFMARKINT)) { - pr_err("Only parameters \"%s\" or \"%s\" may contain a" - " numerical range value.\n", IFMARKINT, OFMARKINT); - return -1; - } - - if (IS_PSTATE_PROPOSER(param)) - return 0; - - tilde_ptr = strchr(value, '~'); - if (!tilde_ptr) { - pr_err("Unable to locate numerical range indicator" - " \"~\" for \"%s\".\n", param->name); - return -1; - } - *tilde_ptr = '\0'; - - left_val_ptr = value; - right_val_ptr = value + strlen(left_val_ptr) + 1; - - if (iscsi_check_numerical_value(param, left_val_ptr) < 0) - return -1; - if (iscsi_check_numerical_value(param, right_val_ptr) < 0) - return -1; - - left_val = simple_strtoul(left_val_ptr, NULL, 0); - right_val = simple_strtoul(right_val_ptr, NULL, 0); - *tilde_ptr = '~'; - - if (right_val < left_val) { - pr_err("Numerical range for parameter \"%s\" contains" - " a right value which is less than the left.\n", - param->name); - return -1; - } - - /* - * For now, enforce reasonable defaults for [I,O]FMarkInt. - */ - tilde_ptr = strchr(param->value, '~'); - if (!tilde_ptr) { - pr_err("Unable to locate numerical range indicator" - " \"~\" for \"%s\".\n", param->name); - return -1; - } - *tilde_ptr = '\0'; - - left_val_ptr = param->value; - right_val_ptr = param->value + strlen(left_val_ptr) + 1; - - local_left_val = simple_strtoul(left_val_ptr, NULL, 0); - *tilde_ptr = '~'; - - if (param->set_param) { - if ((left_val < local_left_val) || - (right_val < local_left_val)) { - pr_err("Passed value range \"%u~%u\" is below" - " minimum left value \"%u\" for key \"%s\"," - " rejecting.\n", left_val, right_val, - local_left_val, param->name); - return -1; - } - } else { - if ((left_val < local_left_val) && - (right_val < local_left_val)) { - pr_err("Received value range \"%u~%u\" is" - " below minimum left value \"%u\" for key" - " \"%s\", rejecting.\n", left_val, right_val, - local_left_val, param->name); - SET_PSTATE_REJECT(param); - if (iscsi_update_param_value(param, REJECT) < 0) - return -1; - } - } - - return 0; -} - static int iscsi_check_string_or_list_value(struct iscsi_param *param, char *value) { if (IS_PSTATE_PROPOSER(param)) @@ -1027,33 +918,6 @@ static int iscsi_check_string_or_list_value(struct iscsi_param *param, char *val return 0; } -/* - * This function is used to pick a value range number, currently just - * returns the lesser of both right values. - */ -static char *iscsi_get_value_from_number_range( - struct iscsi_param *param, - char *value) -{ - char *end_ptr, *tilde_ptr1 = NULL, *tilde_ptr2 = NULL; - u32 acceptor_right_value, proposer_right_value; - - tilde_ptr1 = strchr(value, '~'); - if (!tilde_ptr1) - return NULL; - *tilde_ptr1++ = '\0'; - proposer_right_value = simple_strtoul(tilde_ptr1, &end_ptr, 0); - - tilde_ptr2 = strchr(param->value, '~'); - if (!tilde_ptr2) - return NULL; - *tilde_ptr2++ = '\0'; - acceptor_right_value = simple_strtoul(tilde_ptr2, &end_ptr, 0); - - return (acceptor_right_value >= proposer_right_value) ? - tilde_ptr1 : tilde_ptr2; -} - static char *iscsi_check_valuelist_for_support( struct iscsi_param *param, char *value) @@ -1203,14 +1067,6 @@ static int iscsi_check_acceptor_state(struct iscsi_param *param, char *value, pr_debug("Updated %s to target MXDSL value: %s\n", param->name, param->value); } - - } else if (IS_TYPE_NUMBER_RANGE(param)) { - negoitated_value = iscsi_get_value_from_number_range( - param, value); - if (!negoitated_value) - return -1; - if (iscsi_update_param_value(param, negoitated_value) < 0) - return -1; } else if (IS_TYPE_VALUE_LIST(param)) { negoitated_value = iscsi_check_valuelist_for_support( param, value); @@ -1239,47 +1095,7 @@ static int iscsi_check_proposer_state(struct iscsi_param *param, char *value) return -1; } - if (IS_TYPE_NUMBER_RANGE(param)) { - u32 left_val = 0, right_val = 0, recieved_value = 0; - char *left_val_ptr = NULL, *right_val_ptr = NULL; - char *tilde_ptr = NULL; - - if (!strcmp(value, IRRELEVANT) || !strcmp(value, REJECT)) { - if (iscsi_update_param_value(param, value) < 0) - return -1; - return 0; - } - - tilde_ptr = strchr(value, '~'); - if (tilde_ptr) { - pr_err("Illegal \"~\" in response for \"%s\".\n", - param->name); - return -1; - } - tilde_ptr = strchr(param->value, '~'); - if (!tilde_ptr) { - pr_err("Unable to locate numerical range" - " indicator \"~\" for \"%s\".\n", param->name); - return -1; - } - *tilde_ptr = '\0'; - - left_val_ptr = param->value; - right_val_ptr = param->value + strlen(left_val_ptr) + 1; - left_val = simple_strtoul(left_val_ptr, NULL, 0); - right_val = simple_strtoul(right_val_ptr, NULL, 0); - recieved_value = simple_strtoul(value, NULL, 0); - - *tilde_ptr = '~'; - - if ((recieved_value < left_val) || - (recieved_value > right_val)) { - pr_err("Illegal response \"%s=%u\", value must" - " be between %u and %u.\n", param->name, - recieved_value, left_val, right_val); - return -1; - } - } else if (IS_TYPE_VALUE_LIST(param)) { + if (IS_TYPE_VALUE_LIST(param)) { char *comma_ptr = NULL, *tmp_ptr = NULL; comma_ptr = strchr(value, ','); @@ -1361,9 +1177,6 @@ static int iscsi_check_value(struct iscsi_param *param, char *value) } else if (IS_TYPE_NUMBER(param)) { if (iscsi_check_numerical_value(param, value) < 0) return -1; - } else if (IS_TYPE_NUMBER_RANGE(param)) { - if (iscsi_check_numerical_range_value(param, value) < 0) - return -1; } else if (IS_TYPE_STRING(param) || IS_TYPE_VALUE_LIST(param)) { if (iscsi_check_string_or_list_value(param, value) < 0) return -1; @@ -1483,8 +1296,6 @@ static int iscsi_enforce_integrity_rules( char *tmpptr; u8 DataSequenceInOrder = 0; u8 ErrorRecoveryLevel = 0, SessionType = 0; - u8 IFMarker = 0, OFMarker = 0; - u8 IFMarkInt_Reject = 1, OFMarkInt_Reject = 1; u32 FirstBurstLength = 0, MaxBurstLength = 0; struct iscsi_param *param = NULL; @@ -1503,28 +1314,12 @@ static int iscsi_enforce_integrity_rules( if (!strcmp(param->name, MAXBURSTLENGTH)) MaxBurstLength = simple_strtoul(param->value, &tmpptr, 0); - if (!strcmp(param->name, IFMARKER)) - if (!strcmp(param->value, YES)) - IFMarker = 1; - if (!strcmp(param->name, OFMARKER)) - if (!strcmp(param->value, YES)) - OFMarker = 1; - if (!strcmp(param->name, IFMARKINT)) - if (!strcmp(param->value, REJECT)) - IFMarkInt_Reject = 1; - if (!strcmp(param->name, OFMARKINT)) - if (!strcmp(param->value, REJECT)) - OFMarkInt_Reject = 1; } list_for_each_entry(param, ¶m_list->param_list, p_list) { if (!(param->phase & phase)) continue; - if (!SessionType && (!IS_PSTATE_ACCEPTOR(param) && - (strcmp(param->name, IFMARKER) && - strcmp(param->name, OFMARKER) && - strcmp(param->name, IFMARKINT) && - strcmp(param->name, OFMARKINT)))) + if (!SessionType && !IS_PSTATE_ACCEPTOR(param)) continue; if (!strcmp(param->name, MAXOUTSTANDINGR2T) && DataSequenceInOrder && (ErrorRecoveryLevel > 0)) { @@ -1556,38 +1351,6 @@ static int iscsi_enforce_integrity_rules( param->name, param->value); } } - if (!strcmp(param->name, IFMARKER) && IFMarkInt_Reject) { - if (iscsi_update_param_value(param, NO) < 0) - return -1; - IFMarker = 0; - pr_debug("Reset \"%s\" to \"%s\".\n", - param->name, param->value); - } - if (!strcmp(param->name, OFMARKER) && OFMarkInt_Reject) { - if (iscsi_update_param_value(param, NO) < 0) - return -1; - OFMarker = 0; - pr_debug("Reset \"%s\" to \"%s\".\n", - param->name, param->value); - } - if (!strcmp(param->name, IFMARKINT) && !IFMarker) { - if (!strcmp(param->value, REJECT)) - continue; - param->state &= ~PSTATE_NEGOTIATE; - if (iscsi_update_param_value(param, IRRELEVANT) < 0) - return -1; - pr_debug("Reset \"%s\" to \"%s\".\n", - param->name, param->value); - } - if (!strcmp(param->name, OFMARKINT) && !OFMarker) { - if (!strcmp(param->value, REJECT)) - continue; - param->state &= ~PSTATE_NEGOTIATE; - if (iscsi_update_param_value(param, IRRELEVANT) < 0) - return -1; - pr_debug("Reset \"%s\" to \"%s\".\n", - param->name, param->value); - } } return 0; @@ -1824,24 +1587,6 @@ void iscsi_set_connection_parameters( */ pr_debug("MaxRecvDataSegmentLength: %u\n", ops->MaxRecvDataSegmentLength); - } else if (!strcmp(param->name, OFMARKER)) { - ops->OFMarker = !strcmp(param->value, YES); - pr_debug("OFMarker: %s\n", - param->value); - } else if (!strcmp(param->name, IFMARKER)) { - ops->IFMarker = !strcmp(param->value, YES); - pr_debug("IFMarker: %s\n", - param->value); - } else if (!strcmp(param->name, OFMARKINT)) { - ops->OFMarkInt = - simple_strtoul(param->value, &tmpptr, 0); - pr_debug("OFMarkInt: %s\n", - param->value); - } else if (!strcmp(param->name, IFMARKINT)) { - ops->IFMarkInt = - simple_strtoul(param->value, &tmpptr, 0); - pr_debug("IFMarkInt: %s\n", - param->value); } else if (!strcmp(param->name, INITIATORRECVDATASEGMENTLENGTH)) { ops->InitiatorRecvDataSegmentLength = simple_strtoul(param->value, &tmpptr, 0); diff --git a/drivers/target/iscsi/iscsi_target_parameters.h b/drivers/target/iscsi/iscsi_target_parameters.h index a47046a752aa..a0751e3f0813 100644 --- a/drivers/target/iscsi/iscsi_target_parameters.h +++ b/drivers/target/iscsi/iscsi_target_parameters.h @@ -138,8 +138,8 @@ extern void iscsi_set_session_parameters(struct iscsi_sess_ops *, #define INITIAL_SESSIONTYPE NORMAL #define INITIAL_IFMARKER NO #define INITIAL_OFMARKER NO -#define INITIAL_IFMARKINT "2048~65535" -#define INITIAL_OFMARKINT "2048~65535" +#define INITIAL_IFMARKINT REJECT +#define INITIAL_OFMARKINT REJECT /* * Initial values for iSER parameters following RFC-5046 Section 6 @@ -239,10 +239,9 @@ extern void iscsi_set_session_parameters(struct iscsi_sess_ops *, #define TYPERANGE_AUTH 0x0200 #define TYPERANGE_DIGEST 0x0400 #define TYPERANGE_ISCSINAME 0x0800 -#define TYPERANGE_MARKINT 0x1000 -#define TYPERANGE_SESSIONTYPE 0x2000 -#define TYPERANGE_TARGETADDRESS 0x4000 -#define TYPERANGE_UTF8 0x8000 +#define TYPERANGE_SESSIONTYPE 0x1000 +#define TYPERANGE_TARGETADDRESS 0x2000 +#define TYPERANGE_UTF8 0x4000 #define IS_TYPERANGE_0_TO_2(p) ((p)->type_range & TYPERANGE_0_TO_2) #define IS_TYPERANGE_0_TO_3600(p) ((p)->type_range & TYPERANGE_0_TO_3600) diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index b18edda3e8af..37d23e5e08dc 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c @@ -809,54 +809,6 @@ void iscsit_inc_session_usage_count(struct iscsi_session *sess) spin_unlock_bh(&sess->session_usage_lock); } -/* - * Setup conn->if_marker and conn->of_marker values based upon - * the initial marker-less interval. (see iSCSI v19 A.2) - */ -int iscsit_set_sync_and_steering_values(struct iscsi_conn *conn) -{ - int login_ifmarker_count = 0, login_ofmarker_count = 0, next_marker = 0; - /* - * IFMarkInt and OFMarkInt are negotiated as 32-bit words. - */ - u32 IFMarkInt = (conn->conn_ops->IFMarkInt * 4); - u32 OFMarkInt = (conn->conn_ops->OFMarkInt * 4); - - if (conn->conn_ops->OFMarker) { - /* - * Account for the first Login Command received not - * via iscsi_recv_msg(). - */ - conn->of_marker += ISCSI_HDR_LEN; - if (conn->of_marker <= OFMarkInt) { - conn->of_marker = (OFMarkInt - conn->of_marker); - } else { - login_ofmarker_count = (conn->of_marker / OFMarkInt); - next_marker = (OFMarkInt * (login_ofmarker_count + 1)) + - (login_ofmarker_count * MARKER_SIZE); - conn->of_marker = (next_marker - conn->of_marker); - } - conn->of_marker_offset = 0; - pr_debug("Setting OFMarker value to %u based on Initial" - " Markerless Interval.\n", conn->of_marker); - } - - if (conn->conn_ops->IFMarker) { - if (conn->if_marker <= IFMarkInt) { - conn->if_marker = (IFMarkInt - conn->if_marker); - } else { - login_ifmarker_count = (conn->if_marker / IFMarkInt); - next_marker = (IFMarkInt * (login_ifmarker_count + 1)) + - (login_ifmarker_count * MARKER_SIZE); - conn->if_marker = (next_marker - conn->if_marker); - } - pr_debug("Setting IFMarker value to %u based on Initial" - " Markerless Interval.\n", conn->if_marker); - } - - return 0; -} - struct iscsi_conn *iscsit_get_conn_from_cid(struct iscsi_session *sess, u16 cid) { struct iscsi_conn *conn; diff --git a/drivers/target/iscsi/iscsi_target_util.h b/drivers/target/iscsi/iscsi_target_util.h index 1ab754a671ff..995f1cb29d0e 100644 --- a/drivers/target/iscsi/iscsi_target_util.h +++ b/drivers/target/iscsi/iscsi_target_util.h @@ -34,7 +34,6 @@ extern void iscsit_free_cmd(struct iscsi_cmd *, bool); extern int iscsit_check_session_usage_count(struct iscsi_session *); extern void iscsit_dec_session_usage_count(struct iscsi_session *); extern void iscsit_inc_session_usage_count(struct iscsi_session *); -extern int iscsit_set_sync_and_steering_values(struct iscsi_conn *); extern struct iscsi_conn *iscsit_get_conn_from_cid(struct iscsi_session *, u16); extern struct iscsi_conn *iscsit_get_conn_from_cid_rcfr(struct iscsi_session *, u16); extern void iscsit_check_conn_usage_count(struct iscsi_conn *); diff --git a/include/target/iscsi/iscsi_target_core.h b/include/target/iscsi/iscsi_target_core.h index 54e7af301888..39f3d181d39d 100644 --- a/include/target/iscsi/iscsi_target_core.h +++ b/include/target/iscsi/iscsi_target_core.h @@ -248,10 +248,6 @@ struct iscsi_conn_ops { u8 DataDigest; /* [0,1] == [None,CRC32C] */ u32 MaxRecvDataSegmentLength; /* [512..2**24-1] */ u32 MaxXmitDataSegmentLength; /* [512..2**24-1] */ - u8 OFMarker; /* [0,1] == [No,Yes] */ - u8 IFMarker; /* [0,1] == [No,Yes] */ - u32 OFMarkInt; /* [1..65535] */ - u32 IFMarkInt; /* [1..65535] */ /* * iSER specific connection parameters */ @@ -532,12 +528,6 @@ struct iscsi_conn { u32 exp_statsn; /* Per connection status sequence number */ u32 stat_sn; - /* IFMarkInt's Current Value */ - u32 if_marker; - /* OFMarkInt's Current Value */ - u32 of_marker; - /* Used for calculating OFMarker offset to next PDU */ - u32 of_marker_offset; #define IPV6_ADDRESS_SPACE 48 unsigned char login_ip[IPV6_ADDRESS_SPACE]; unsigned char local_ip[IPV6_ADDRESS_SPACE]; -- cgit v1.2.3-70-g09d2 From 814e5b45182f4aaf6c0b0deac7104bc2cba5109e Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 20 Apr 2015 15:00:30 +0200 Subject: target: fix DPO and FUA bit checks Drivers may override the WCE flag, in which case the DPOFUA flag in MODE SENSE might differ from the check used to reject invalid FUA bits in sbc_check_dpofua. Also now that we reject invalid FUA bits early there is no need to duplicate the same buggy check down in the fileio code. As the DPOFUA flag controls th support for FUA bits on read and write commands as well as DPO key off all the checks off a single helper, and deprecate the emulate_dpo and emulate_fua_read attributs. This fixes various failures in the libiscsi testsuite. Personally I'd prefer to also remove the emulate_fua_write attribute as there is no good reason to disable it, but I'll leave that for a separate discussion. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_device.c | 30 +++++++----------------------- drivers/target/target_core_file.c | 4 +--- drivers/target/target_core_internal.h | 2 ++ drivers/target/target_core_sbc.c | 5 +++-- drivers/target/target_core_spc.c | 12 ++++++++---- drivers/target/target_core_transport.c | 19 +++++++++++++++++++ include/target/target_core_base.h | 6 ------ 7 files changed, 40 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index ce5f768181ff..9ee194d1cd4b 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -760,16 +760,8 @@ EXPORT_SYMBOL(se_dev_set_emulate_model_alias); int se_dev_set_emulate_dpo(struct se_device *dev, int flag) { - if (flag != 0 && flag != 1) { - pr_err("Illegal value %d\n", flag); - return -EINVAL; - } - - if (flag) { - pr_err("dpo_emulated not supported\n"); - return -EINVAL; - } - + printk_once(KERN_WARNING + "ignoring deprecated emulate_dpo attribute\n"); return 0; } EXPORT_SYMBOL(se_dev_set_emulate_dpo); @@ -799,16 +791,8 @@ EXPORT_SYMBOL(se_dev_set_emulate_fua_write); int se_dev_set_emulate_fua_read(struct se_device *dev, int flag) { - if (flag != 0 && flag != 1) { - pr_err("Illegal value %d\n", flag); - return -EINVAL; - } - - if (flag) { - pr_err("ua read emulated not supported\n"); - return -EINVAL; - } - + printk_once(KERN_WARNING + "ignoring deprecated emulate_fua_read attribute\n"); return 0; } EXPORT_SYMBOL(se_dev_set_emulate_fua_read); @@ -1513,9 +1497,9 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name) dev->dev_attrib.da_dev = dev; dev->dev_attrib.emulate_model_alias = DA_EMULATE_MODEL_ALIAS; - dev->dev_attrib.emulate_dpo = DA_EMULATE_DPO; - dev->dev_attrib.emulate_fua_write = DA_EMULATE_FUA_WRITE; - dev->dev_attrib.emulate_fua_read = DA_EMULATE_FUA_READ; + dev->dev_attrib.emulate_dpo = 1; + dev->dev_attrib.emulate_fua_write = 1; + dev->dev_attrib.emulate_fua_read = 1; dev->dev_attrib.emulate_write_cache = DA_EMULATE_WRITE_CACHE; dev->dev_attrib.emulate_ua_intlck_ctrl = DA_EMULATE_UA_INTLLCK_CTRL; dev->dev_attrib.emulate_tas = DA_EMULATE_TAS; diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index fe6c19c1e001..e865885352da 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -610,9 +610,7 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, * for SCSI WRITEs with Forced Unit Access (FUA) set. * Allow this to happen independent of WCE=0 setting. */ - if (ret > 0 && - dev->dev_attrib.emulate_fua_write > 0 && - (cmd->se_cmd_flags & SCF_FUA)) { + if (ret > 0 && (cmd->se_cmd_flags & SCF_FUA)) { loff_t start = cmd->t_task_lba * dev->dev_attrib.block_size; loff_t end; diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index 68bd7f5d9f73..75338c348be4 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -81,6 +81,8 @@ int transport_clear_lun_ref(struct se_lun *); void transport_send_task_abort(struct se_cmd *); sense_reason_t target_cmd_size_check(struct se_cmd *cmd, unsigned int size); void target_qf_do_work(struct work_struct *work); +bool target_check_wce(struct se_device *dev); +bool target_check_fua(struct se_device *dev); /* target_core_stat.c */ void target_stat_setup_dev_default_groups(struct se_device *); diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 3df2cd538478..d441975604db 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -738,14 +738,15 @@ static int sbc_check_dpofua(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb) { if (cdb[1] & 0x10) { - if (!dev->dev_attrib.emulate_dpo) { + /* see explanation in spc_emulate_modesense */ + if (!target_check_fua(dev)) { pr_err("Got CDB: 0x%02x with DPO bit set, but device" " does not advertise support for DPO\n", cdb[0]); return -EINVAL; } } if (cdb[1] & 0x8) { - if (!dev->dev_attrib.emulate_fua_write || !se_dev_check_wce(dev)) { + if (!target_check_fua(dev)) { pr_err("Got CDB: 0x%02x with FUA bit set, but device" " does not advertise support for FUA write\n", cdb[0]); diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index 7912aa124385..988c158cf65d 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -481,7 +481,7 @@ spc_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf) buf[5] = 0x07; /* If WriteCache emulation is enabled, set V_SUP */ - if (se_dev_check_wce(dev)) + if (target_check_wce(dev)) buf[6] = 0x01; /* If an LBA map is present set R_SUP */ spin_lock(&cmd->se_dev->t10_alua.lba_map_lock); @@ -888,7 +888,7 @@ static int spc_modesense_caching(struct se_cmd *cmd, u8 pc, u8 *p) if (pc == 1) goto out; - if (se_dev_check_wce(dev)) + if (target_check_wce(dev)) p[2] = 0x04; /* Write Cache Enable */ p[12] = 0x20; /* Disabled Read Ahead */ @@ -1000,8 +1000,12 @@ static sense_reason_t spc_emulate_modesense(struct se_cmd *cmd) (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY))) spc_modesense_write_protect(&buf[length], type); - if ((se_dev_check_wce(dev)) && - (dev->dev_attrib.emulate_fua_write > 0)) + /* + * SBC only allows us to enable FUA and DPO together. Fortunately + * DPO is explicitly specified as a hint, so a noop is a perfectly + * valid implementation. + */ + if (target_check_fua(dev)) spc_modesense_dpofua(&buf[length], type); ++length; diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 105f4fd0fad4..231812d61357 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -3075,3 +3075,22 @@ int transport_generic_handle_tmr( return 0; } EXPORT_SYMBOL(transport_generic_handle_tmr); + +bool +target_check_wce(struct se_device *dev) +{ + bool wce = false; + + if (dev->transport->get_write_cache) + wce = dev->transport->get_write_cache(dev); + else if (dev->dev_attrib.emulate_write_cache > 0) + wce = true; + + return wce; +} + +bool +target_check_fua(struct se_device *dev) +{ + return target_check_wce(dev) && dev->dev_attrib.emulate_fua_write > 0; +} diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 480e9f82dfea..7f4c7de3a4ce 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -79,12 +79,6 @@ #define DA_MAX_WRITE_SAME_LEN 0 /* Use a model alias based on the configfs backend device name */ #define DA_EMULATE_MODEL_ALIAS 0 -/* Emulation for Direct Page Out */ -#define DA_EMULATE_DPO 0 -/* Emulation for Forced Unit Access WRITEs */ -#define DA_EMULATE_FUA_WRITE 1 -/* Emulation for Forced Unit Access READs */ -#define DA_EMULATE_FUA_READ 0 /* Emulation for WriteCache and SYNCHRONIZE_CACHE */ #define DA_EMULATE_WRITE_CACHE 0 /* Emulation for UNIT ATTENTION Interlock Control */ -- cgit v1.2.3-70-g09d2 From 2bc396a2529ae8a2287f17a49d893ce790e19110 Mon Sep 17 00:00:00 2001 From: Ilias Tsitsimpis Date: Thu, 23 Apr 2015 21:30:05 +0300 Subject: driver/user: Don't warn for DMA_NONE data direction Some SCSI commands (for example the TEST UNIT READY command) do not carry data and so data_direction is DMA_NONE. Patch TCMU to not print a warning message about unknown data direction, when it is DMA_NONE. Signed-off-by: Ilias Tsitsimpis Signed-off-by: Vangelis Koukis Reviewed-by: Andy Grover Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_user.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 07d2996d8c1f..50387c1d5e38 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -518,8 +518,9 @@ static void tcmu_handle_completion(struct tcmu_cmd *cmd, struct tcmu_cmd_entry * } else if (se_cmd->data_direction == DMA_TO_DEVICE) { UPDATE_HEAD(udev->data_tail, cmd->data_length, udev->data_size); - } else { - pr_warn("TCMU: data direction was %d!\n", se_cmd->data_direction); + } else if (se_cmd->data_direction != DMA_NONE) { + pr_warn("TCMU: data direction was %d!\n", + se_cmd->data_direction); } target_complete_cmd(cmd->se_cmd, entry->rsp.scsi_status); -- cgit v1.2.3-70-g09d2 From 9736f4ad7c6dd79eea36c7fb537a27bbd802582a Mon Sep 17 00:00:00 2001 From: Ilias Tsitsimpis Date: Thu, 23 Apr 2015 21:30:06 +0300 Subject: target/loop: Enable VARLEN CDB support Field shost->max_cmd_len is used to inform Linux / the SCSI midlayer of the maximum CDB size an LLD is capable of handling. Set this field to SCSI_MAX_VARLEN_CDB_SIZE for target, to enable support for variable-sized CDBs (0x7E). Also remove the definition of TL_SCSI_MAX_CMD_LEN since it is now redundant. Signed-off-by: Ilias Tsitsimpis Signed-off-by: Vangelis Koukis Reviewed-by: Andy Grover Signed-off-by: Nicholas Bellinger --- drivers/target/loopback/tcm_loop.c | 2 +- drivers/target/loopback/tcm_loop.h | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 51f0c895c6a5..b863ce894977 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -409,7 +409,7 @@ static int tcm_loop_driver_probe(struct device *dev) sh->max_id = 2; sh->max_lun = 0; sh->max_channel = 0; - sh->max_cmd_len = TL_SCSI_MAX_CMD_LEN; + sh->max_cmd_len = SCSI_MAX_VARLEN_CDB_SIZE; host_prot = SHOST_DIF_TYPE1_PROTECTION | SHOST_DIF_TYPE2_PROTECTION | SHOST_DIF_TYPE3_PROTECTION | SHOST_DIX_TYPE1_PROTECTION | diff --git a/drivers/target/loopback/tcm_loop.h b/drivers/target/loopback/tcm_loop.h index 1e72ff77cac9..433e595e5daa 100644 --- a/drivers/target/loopback/tcm_loop.h +++ b/drivers/target/loopback/tcm_loop.h @@ -2,11 +2,6 @@ #define TL_WWN_ADDR_LEN 256 #define TL_TPGS_PER_HBA 32 -/* - * Used in tcm_loop_driver_probe() for struct Scsi_Host->max_cmd_len - */ -#define TL_SCSI_MAX_CMD_LEN 32 - struct tcm_loop_cmd { /* State of Linux/SCSI CDB+Data descriptor */ u32 sc_cmd_state; -- cgit v1.2.3-70-g09d2 From b32bd0a8ee6a19f9b70aa4fcb9bfc802b105ce05 Mon Sep 17 00:00:00 2001 From: Ilias Tsitsimpis Date: Thu, 23 Apr 2015 21:30:07 +0300 Subject: target/transport: Always initialize bidi fields in se_cmd Fields t_bidi_data_sg and t_bidi_data_nents are set only in the presence of BIDI commands. This means that the underlying code (for example TCMU) cannot inspect them when the SCSI command is not a BIDI one. Ensure the code always initializes these fields with the given values, even when the SCSI command is not a BIDI one. Set t_bidi_data_sg to sgl_bidi (which should be NULL for non-BIDI commands) and t_bidi_data_nents to sgl_bidi_count (which should be 0 for non-BIDI commands). This allows the underlying code to use these fields unconditionally. Signed-off-by: Ilias Tsitsimpis Signed-off-by: Vangelis Koukis Reviewed-by: Andy Grover Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 231812d61357..078d32102cce 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1353,11 +1353,9 @@ transport_generic_map_mem_to_cmd(struct se_cmd *cmd, struct scatterlist *sgl, cmd->t_data_sg = sgl; cmd->t_data_nents = sgl_count; + cmd->t_bidi_data_sg = sgl_bidi; + cmd->t_bidi_data_nents = sgl_bidi_count; - if (sgl_bidi && sgl_bidi_count) { - cmd->t_bidi_data_sg = sgl_bidi; - cmd->t_bidi_data_nents = sgl_bidi_count; - } cmd->se_cmd_flags |= SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC; return 0; } -- cgit v1.2.3-70-g09d2 From f97ec7db1606875666366bfcba8476f8c917db96 Mon Sep 17 00:00:00 2001 From: Ilias Tsitsimpis Date: Thu, 23 Apr 2015 21:47:00 +0300 Subject: target/user: Refactor data area allocation code Introduce alloc_and_scatter_data_area()/gather_and_free_data_area() functions that allocate/deallocate space from the data area and copy data to/from a given scatter-gather list. These functions are needed so the next patch, introducing support for bidirectional commands in TCMU, can use the same code path both for t_data_sg and for t_bidi_data_sg. Signed-off-by: Ilias Tsitsimpis Signed-off-by: Vangelis Koukis Reviewed-by: Andy Grover Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_user.c | 189 +++++++++++++++++++++----------------- 1 file changed, 106 insertions(+), 83 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 50387c1d5e38..2b0d26e268be 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2013 Shaohua Li * Copyright (C) 2014 Red Hat, Inc. + * Copyright (C) 2015 Arrikto, Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -224,9 +225,104 @@ static inline size_t head_to_end(size_t head, size_t size) #define UPDATE_HEAD(head, used, size) smp_store_release(&head, ((head % size) + used) % size) +static void alloc_and_scatter_data_area(struct tcmu_dev *udev, + struct scatterlist *data_sg, unsigned int data_nents, + struct iovec **iov, int *iov_cnt, bool copy_data) +{ + int i; + void *from, *to; + size_t copy_bytes; + struct scatterlist *sg; + + for_each_sg(data_sg, sg, data_nents, i) { + copy_bytes = min_t(size_t, sg->length, + head_to_end(udev->data_head, udev->data_size)); + from = kmap_atomic(sg_page(sg)) + sg->offset; + to = (void *) udev->mb_addr + udev->data_off + udev->data_head; + + if (copy_data) { + memcpy(to, from, copy_bytes); + tcmu_flush_dcache_range(to, copy_bytes); + } + + /* Even iov_base is relative to mb_addr */ + (*iov)->iov_len = copy_bytes; + (*iov)->iov_base = (void __user *) udev->data_off + + udev->data_head; + (*iov_cnt)++; + (*iov)++; + + UPDATE_HEAD(udev->data_head, copy_bytes, udev->data_size); + + /* Uh oh, we wrapped the buffer. Must split sg across 2 iovs. */ + if (sg->length != copy_bytes) { + from += copy_bytes; + copy_bytes = sg->length - copy_bytes; + + (*iov)->iov_len = copy_bytes; + (*iov)->iov_base = (void __user *) udev->data_off + + udev->data_head; + + if (copy_data) { + to = (void *) udev->mb_addr + + udev->data_off + udev->data_head; + memcpy(to, from, copy_bytes); + tcmu_flush_dcache_range(to, copy_bytes); + } + + (*iov_cnt)++; + (*iov)++; + + UPDATE_HEAD(udev->data_head, + copy_bytes, udev->data_size); + } + + kunmap_atomic(from); + } +} + +static void gather_and_free_data_area(struct tcmu_dev *udev, + struct scatterlist *data_sg, unsigned int data_nents) +{ + int i; + void *from, *to; + size_t copy_bytes; + struct scatterlist *sg; + + /* It'd be easier to look at entry's iovec again, but UAM */ + for_each_sg(data_sg, sg, data_nents, i) { + copy_bytes = min_t(size_t, sg->length, + head_to_end(udev->data_tail, udev->data_size)); + + to = kmap_atomic(sg_page(sg)) + sg->offset; + WARN_ON(sg->length + sg->offset > PAGE_SIZE); + from = (void *) udev->mb_addr + + udev->data_off + udev->data_tail; + tcmu_flush_dcache_range(from, copy_bytes); + memcpy(to, from, copy_bytes); + + UPDATE_HEAD(udev->data_tail, copy_bytes, udev->data_size); + + /* Uh oh, wrapped the data buffer for this sg's data */ + if (sg->length != copy_bytes) { + from = (void *) udev->mb_addr + + udev->data_off + udev->data_tail; + WARN_ON(udev->data_tail); + to += copy_bytes; + copy_bytes = sg->length - copy_bytes; + tcmu_flush_dcache_range(from, copy_bytes); + memcpy(to, from, copy_bytes); + + UPDATE_HEAD(udev->data_tail, + copy_bytes, udev->data_size); + } + kunmap_atomic(to); + } +} + /* - * We can't queue a command until we have space available on the cmd ring *and* space - * space avail on the data ring. + * We can't queue a command until we have space available on the cmd ring *and* + * space available on the data ring. * * Called with ring lock held. */ @@ -274,12 +370,11 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) size_t base_command_size, command_size; struct tcmu_mailbox *mb; struct tcmu_cmd_entry *entry; - int i; - struct scatterlist *sg; struct iovec *iov; - int iov_cnt = 0; + int iov_cnt; uint32_t cmd_head; uint64_t cdb_off; + bool copy_to_data_area; if (test_bit(TCMU_DEV_BIT_BROKEN, &udev->flags)) return -EINVAL; @@ -360,49 +455,10 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) * Fix up iovecs, and handle if allocation in data ring wrapped. */ iov = &entry->req.iov[0]; - for_each_sg(se_cmd->t_data_sg, sg, se_cmd->t_data_nents, i) { - size_t copy_bytes = min((size_t)sg->length, - head_to_end(udev->data_head, udev->data_size)); - void *from = kmap_atomic(sg_page(sg)) + sg->offset; - void *to = (void *) mb + udev->data_off + udev->data_head; - - if (tcmu_cmd->se_cmd->data_direction == DMA_TO_DEVICE) { - memcpy(to, from, copy_bytes); - tcmu_flush_dcache_range(to, copy_bytes); - } - - /* Even iov_base is relative to mb_addr */ - iov->iov_len = copy_bytes; - iov->iov_base = (void __user *) udev->data_off + - udev->data_head; - iov_cnt++; - iov++; - - UPDATE_HEAD(udev->data_head, copy_bytes, udev->data_size); - - /* Uh oh, we wrapped the buffer. Must split sg across 2 iovs. */ - if (sg->length != copy_bytes) { - from += copy_bytes; - copy_bytes = sg->length - copy_bytes; - - iov->iov_len = copy_bytes; - iov->iov_base = (void __user *) udev->data_off + - udev->data_head; - - if (se_cmd->data_direction == DMA_TO_DEVICE) { - to = (void *) mb + udev->data_off + udev->data_head; - memcpy(to, from, copy_bytes); - tcmu_flush_dcache_range(to, copy_bytes); - } - - iov_cnt++; - iov++; - - UPDATE_HEAD(udev->data_head, copy_bytes, udev->data_size); - } - - kunmap_atomic(from); - } + iov_cnt = 0; + copy_to_data_area = (se_cmd->data_direction == DMA_TO_DEVICE); + alloc_and_scatter_data_area(udev, se_cmd->t_data_sg, + se_cmd->t_data_nents, &iov, &iov_cnt, copy_to_data_area); entry->req.iov_cnt = iov_cnt; entry->req.iov_bidi_cnt = 0; entry->req.iov_dif_cnt = 0; @@ -481,41 +537,8 @@ static void tcmu_handle_completion(struct tcmu_cmd *cmd, struct tcmu_cmd_entry * UPDATE_HEAD(udev->data_tail, cmd->data_length, udev->data_size); } else if (se_cmd->data_direction == DMA_FROM_DEVICE) { - struct scatterlist *sg; - int i; - - /* It'd be easier to look at entry's iovec again, but UAM */ - for_each_sg(se_cmd->t_data_sg, sg, se_cmd->t_data_nents, i) { - size_t copy_bytes; - void *to; - void *from; - - copy_bytes = min((size_t)sg->length, - head_to_end(udev->data_tail, udev->data_size)); - - to = kmap_atomic(sg_page(sg)) + sg->offset; - WARN_ON(sg->length + sg->offset > PAGE_SIZE); - from = (void *) udev->mb_addr + udev->data_off + udev->data_tail; - tcmu_flush_dcache_range(from, copy_bytes); - memcpy(to, from, copy_bytes); - - UPDATE_HEAD(udev->data_tail, copy_bytes, udev->data_size); - - /* Uh oh, wrapped the data buffer for this sg's data */ - if (sg->length != copy_bytes) { - from = (void *) udev->mb_addr + udev->data_off + udev->data_tail; - WARN_ON(udev->data_tail); - to += copy_bytes; - copy_bytes = sg->length - copy_bytes; - tcmu_flush_dcache_range(from, copy_bytes); - memcpy(to, from, copy_bytes); - - UPDATE_HEAD(udev->data_tail, copy_bytes, udev->data_size); - } - - kunmap_atomic(to); - } - + gather_and_free_data_area(udev, + se_cmd->t_data_sg, se_cmd->t_data_nents); } else if (se_cmd->data_direction == DMA_TO_DEVICE) { UPDATE_HEAD(udev->data_tail, cmd->data_length, udev->data_size); } else if (se_cmd->data_direction != DMA_NONE) { -- cgit v1.2.3-70-g09d2 From e4648b014e03baee45d5f5146c1219b19e4e5f2f Mon Sep 17 00:00:00 2001 From: Ilias Tsitsimpis Date: Thu, 23 Apr 2015 21:30:09 +0300 Subject: target/user: Add support for bidirectional commands Enable TCMU to handle bidirectional SCSI commands. In such cases, entries in iov[] cover both the Data-In and the Data-Out buffers. The first iov_cnt entries correspond to the Data-Out buffer, while the remaining iov_bidi_cnt entries correspond to the Data-In buffer. Signed-off-by: Ilias Tsitsimpis Signed-off-by: Vangelis Koukis Reviewed-by: Andy Grover Signed-off-by: Nicholas Bellinger --- Documentation/target/tcmu-design.txt | 2 +- drivers/target/target_core_user.c | 29 ++++++++++++++++++++++++----- 2 files changed, 25 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/Documentation/target/tcmu-design.txt b/Documentation/target/tcmu-design.txt index 263b907517ac..bef81e42788f 100644 --- a/Documentation/target/tcmu-design.txt +++ b/Documentation/target/tcmu-design.txt @@ -152,7 +152,7 @@ overall shared memory region, not the entry. The data in/out buffers are accessible via tht req.iov[] array. iov_cnt contains the number of entries in iov[] needed to describe either the Data-In or Data-Out buffers. For bidirectional commands, iov_cnt specifies how many iovec -entries cover the Data-Out area, and iov_bidi_count specifies how many +entries cover the Data-Out area, and iov_bidi_cnt specifies how many iovec entries immediately after that in iov[] cover the Data-In area. Just like other fields, iov.iov_base is an offset from the start of the region. diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 2b0d26e268be..60330e00f59d 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -167,6 +167,11 @@ static struct tcmu_cmd *tcmu_alloc_cmd(struct se_cmd *se_cmd) tcmu_cmd->tcmu_dev = udev; tcmu_cmd->data_length = se_cmd->data_length; + if (se_cmd->se_cmd_flags & SCF_BIDI) { + BUG_ON(!(se_cmd->t_bidi_data_sg && se_cmd->t_bidi_data_nents)); + tcmu_cmd->data_length += se_cmd->t_bidi_data_sg->length; + } + tcmu_cmd->deadline = jiffies + msecs_to_jiffies(TCMU_TIME_OUT); idr_preload(GFP_KERNEL); @@ -387,7 +392,8 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) * b/c size == offsetof one-past-element. */ base_command_size = max(offsetof(struct tcmu_cmd_entry, - req.iov[se_cmd->t_data_nents + 2]), + req.iov[se_cmd->t_bidi_data_nents + + se_cmd->t_data_nents + 2]), sizeof(struct tcmu_cmd_entry)); command_size = base_command_size + round_up(scsi_command_size(se_cmd->t_task_cdb), TCMU_OP_ALIGN_SIZE); @@ -456,13 +462,19 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) */ iov = &entry->req.iov[0]; iov_cnt = 0; - copy_to_data_area = (se_cmd->data_direction == DMA_TO_DEVICE); + copy_to_data_area = (se_cmd->data_direction == DMA_TO_DEVICE + || se_cmd->se_cmd_flags & SCF_BIDI); alloc_and_scatter_data_area(udev, se_cmd->t_data_sg, se_cmd->t_data_nents, &iov, &iov_cnt, copy_to_data_area); entry->req.iov_cnt = iov_cnt; - entry->req.iov_bidi_cnt = 0; entry->req.iov_dif_cnt = 0; + /* Handle BIDI commands */ + iov_cnt = 0; + alloc_and_scatter_data_area(udev, se_cmd->t_bidi_data_sg, + se_cmd->t_bidi_data_nents, &iov, &iov_cnt, false); + entry->req.iov_bidi_cnt = iov_cnt; + /* All offsets relative to mb_addr, not start of entry! */ cdb_off = CMDR_OFF + cmd_head + base_command_size; memcpy((void *) mb + cdb_off, se_cmd->t_task_cdb, scsi_command_size(se_cmd->t_task_cdb)); @@ -535,8 +547,15 @@ static void tcmu_handle_completion(struct tcmu_cmd *cmd, struct tcmu_cmd_entry * se_cmd->scsi_sense_length); UPDATE_HEAD(udev->data_tail, cmd->data_length, udev->data_size); - } - else if (se_cmd->data_direction == DMA_FROM_DEVICE) { + } else if (se_cmd->se_cmd_flags & SCF_BIDI) { + /* Discard data_out buffer */ + UPDATE_HEAD(udev->data_tail, + (size_t)se_cmd->t_data_sg->length, udev->data_size); + + /* Get Data-In buffer */ + gather_and_free_data_area(udev, + se_cmd->t_bidi_data_sg, se_cmd->t_bidi_data_nents); + } else if (se_cmd->data_direction == DMA_FROM_DEVICE) { gather_and_free_data_area(udev, se_cmd->t_data_sg, se_cmd->t_data_nents); } else if (se_cmd->data_direction == DMA_TO_DEVICE) { -- cgit v1.2.3-70-g09d2 From afc16604c06414223478df3e42301ab630b9960a Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 27 Apr 2015 13:52:36 +0200 Subject: target: Remove first argument of target_{get,put}_sess_cmd() The first argument of these two functions is always identical to se_cmd->se_sess. Hence remove the first argument. Signed-off-by: Bart Van Assche Reviewed-by: Sagi Grimberg Reviewed-by: Christoph Hellwig Cc: Andy Grover Cc: Cc: Felipe Balbi Cc: Michael S. Tsirkin Signed-off-by: Nicholas Bellinger --- drivers/infiniband/ulp/isert/ib_isert.c | 6 +++--- drivers/infiniband/ulp/srpt/ib_srpt.c | 10 +++++----- drivers/scsi/qla2xxx/tcm_qla2xxx.c | 2 +- drivers/target/iscsi/iscsi_target.c | 15 +++++++-------- drivers/target/iscsi/iscsi_target_configfs.c | 2 +- drivers/target/iscsi/iscsi_target_util.c | 4 ++-- drivers/target/target_core_tmr.c | 2 +- drivers/target/target_core_transport.c | 20 ++++++++++---------- drivers/vhost/scsi.c | 2 +- include/target/target_core_fabric.h | 4 ++-- 10 files changed, 33 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c index 3f40319a55da..9e3662cce612 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.c +++ b/drivers/infiniband/ulp/isert/ib_isert.c @@ -1332,7 +1332,7 @@ sequence_cmd: if (!rc && dump_payload == false && unsol_data) iscsit_set_unsoliticed_dataout(cmd); else if (dump_payload && imm_data) - target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd); + target_put_sess_cmd(&cmd->se_cmd); return 0; } @@ -1757,7 +1757,7 @@ isert_put_cmd(struct isert_cmd *isert_cmd, bool comp_err) cmd->se_cmd.t_state == TRANSPORT_WRITE_PENDING) { struct se_cmd *se_cmd = &cmd->se_cmd; - target_put_sess_cmd(se_cmd->se_sess, se_cmd); + target_put_sess_cmd(se_cmd); } } @@ -1930,7 +1930,7 @@ isert_completion_rdma_read(struct iser_tx_desc *tx_desc, spin_unlock_bh(&cmd->istate_lock); if (ret) { - target_put_sess_cmd(se_cmd->se_sess, se_cmd); + target_put_sess_cmd(se_cmd); transport_send_check_condition_and_sense(se_cmd, se_cmd->pi_err, 0); } else { diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 9b84b4c0a000..6fbc7bc824d2 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -1334,7 +1334,7 @@ static int srpt_abort_cmd(struct srpt_send_ioctx *ioctx) BUG_ON(ch->sess == NULL); - target_put_sess_cmd(ch->sess, &ioctx->cmd); + target_put_sess_cmd(&ioctx->cmd); goto out; } @@ -1365,11 +1365,11 @@ static int srpt_abort_cmd(struct srpt_send_ioctx *ioctx) * not been received in time. */ srpt_unmap_sg_to_ib_sge(ioctx->ch, ioctx); - target_put_sess_cmd(ioctx->ch->sess, &ioctx->cmd); + target_put_sess_cmd(&ioctx->cmd); break; case SRPT_STATE_MGMT_RSP_SENT: srpt_set_cmd_state(ioctx, SRPT_STATE_DONE); - target_put_sess_cmd(ioctx->ch->sess, &ioctx->cmd); + target_put_sess_cmd(&ioctx->cmd); break; default: WARN(1, "Unexpected command state (%d)", state); @@ -1679,7 +1679,7 @@ static int srpt_check_stop_free(struct se_cmd *cmd) struct srpt_send_ioctx *ioctx = container_of(cmd, struct srpt_send_ioctx, cmd); - return target_put_sess_cmd(ioctx->ch->sess, &ioctx->cmd); + return target_put_sess_cmd(&ioctx->cmd); } /** @@ -3074,7 +3074,7 @@ static void srpt_queue_response(struct se_cmd *cmd) ioctx->tag); srpt_unmap_sg_to_ib_sge(ch, ioctx); srpt_set_cmd_state(ioctx, SRPT_STATE_DONE); - target_put_sess_cmd(ioctx->ch->sess, &ioctx->cmd); + target_put_sess_cmd(&ioctx->cmd); } } diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 5c9e680aa375..8a6c87547303 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -429,7 +429,7 @@ static int tcm_qla2xxx_check_stop_free(struct se_cmd *se_cmd) cmd->cmd_flags |= BIT_14; } - return target_put_sess_cmd(se_cmd->se_sess, se_cmd); + return target_put_sess_cmd(se_cmd); } /* tcm_qla2xxx_release_cmd - Callback from TCM Core to release underlying diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 21620c751071..866c167c0986 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -715,7 +715,7 @@ static int iscsit_add_reject_from_cmd( */ if (cmd->se_cmd.se_tfo != NULL) { pr_debug("iscsi reject: calling target_put_sess_cmd >>>>>>\n"); - target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd); + target_put_sess_cmd(&cmd->se_cmd); } return -1; } @@ -1001,7 +1001,7 @@ int iscsit_setup_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, hdr->cmdsn, be32_to_cpu(hdr->data_length), payload_length, conn->cid); - target_get_sess_cmd(conn->sess->se_sess, &cmd->se_cmd, true); + target_get_sess_cmd(&cmd->se_cmd, true); cmd->sense_reason = transport_lookup_cmd_lun(&cmd->se_cmd, scsilun_to_int(&hdr->lun)); @@ -1067,7 +1067,7 @@ int iscsit_process_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) return -1; else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) { - target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd); + target_put_sess_cmd(&cmd->se_cmd); return 0; } } @@ -1083,7 +1083,7 @@ int iscsit_process_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, if (!cmd->sense_reason) return 0; - target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd); + target_put_sess_cmd(&cmd->se_cmd); return 0; } @@ -1114,7 +1114,6 @@ static int iscsit_get_immediate_data(struct iscsi_cmd *cmd, struct iscsi_scsi_req *hdr, bool dump_payload) { - struct iscsi_conn *conn = cmd->conn; int cmdsn_ret = 0, immed_ret = IMMEDIATE_DATA_NORMAL_OPERATION; /* * Special case for Unsupported SAM WRITE Opcodes and ImmediateData=Yes. @@ -1141,7 +1140,7 @@ after_immediate_data: rc = iscsit_dump_data_payload(cmd->conn, cmd->first_burst_len, 1); - target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd); + target_put_sess_cmd(&cmd->se_cmd); return rc; } else if (cmd->unsolicited_data) iscsit_set_unsoliticed_dataout(cmd); @@ -1810,7 +1809,7 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, conn->sess->se_sess, 0, DMA_NONE, TCM_SIMPLE_TAG, cmd->sense_buffer + 2); - target_get_sess_cmd(conn->sess->se_sess, &cmd->se_cmd, true); + target_get_sess_cmd(&cmd->se_cmd, true); sess_ref = true; switch (function) { @@ -1952,7 +1951,7 @@ attach: */ if (sess_ref) { pr_debug("Handle TMR, using sess_ref=true check\n"); - target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd); + target_put_sess_cmd(&cmd->se_cmd); } iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state); diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 469fce44ebad..568e478615a5 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -1967,7 +1967,7 @@ static void lio_set_default_node_attributes(struct se_node_acl *se_acl) static int lio_check_stop_free(struct se_cmd *se_cmd) { - return target_put_sess_cmd(se_cmd->se_sess, se_cmd); + return target_put_sess_cmd(se_cmd); } static void lio_release_cmd(struct se_cmd *se_cmd) diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index 37d23e5e08dc..c1582e88191e 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c @@ -746,7 +746,7 @@ void iscsit_free_cmd(struct iscsi_cmd *cmd, bool shutdown) rc = transport_generic_free_cmd(&cmd->se_cmd, shutdown); if (!rc && shutdown && se_cmd && se_cmd->se_sess) { __iscsit_free_cmd(cmd, true, shutdown); - target_put_sess_cmd(se_cmd->se_sess, se_cmd); + target_put_sess_cmd(se_cmd); } break; case ISCSI_OP_REJECT: @@ -762,7 +762,7 @@ void iscsit_free_cmd(struct iscsi_cmd *cmd, bool shutdown) rc = transport_generic_free_cmd(&cmd->se_cmd, shutdown); if (!rc && shutdown && se_cmd->se_sess) { __iscsit_free_cmd(cmd, true, shutdown); - target_put_sess_cmd(se_cmd->se_sess, se_cmd); + target_put_sess_cmd(se_cmd); } break; } diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c index 315ec3458eeb..b2e169fba3c6 100644 --- a/drivers/target/target_core_tmr.c +++ b/drivers/target/target_core_tmr.c @@ -153,7 +153,7 @@ void core_tmr_abort_task( cancel_work_sync(&se_cmd->work); transport_wait_for_tasks(se_cmd); - target_put_sess_cmd(se_sess, se_cmd); + target_put_sess_cmd(se_cmd); transport_cmd_finish_abort(se_cmd, true); printk("ABORT_TASK: Sending TMR_FUNCTION_COMPLETE for" diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 078d32102cce..9dc1bd5f0e6b 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1417,7 +1417,7 @@ int target_submit_cmd_map_sgls(struct se_cmd *se_cmd, struct se_session *se_sess * for fabrics using TARGET_SCF_ACK_KREF that expect a second * kref_put() to happen during fabric packet acknowledgement. */ - ret = target_get_sess_cmd(se_sess, se_cmd, (flags & TARGET_SCF_ACK_KREF)); + ret = target_get_sess_cmd(se_cmd, flags & TARGET_SCF_ACK_KREF); if (ret) return ret; /* @@ -1431,7 +1431,7 @@ int target_submit_cmd_map_sgls(struct se_cmd *se_cmd, struct se_session *se_sess rc = transport_lookup_cmd_lun(se_cmd, unpacked_lun); if (rc) { transport_send_check_condition_and_sense(se_cmd, rc, 0); - target_put_sess_cmd(se_sess, se_cmd); + target_put_sess_cmd(se_cmd); return 0; } @@ -1582,7 +1582,7 @@ int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess, se_cmd->se_tmr_req->ref_task_tag = tag; /* See target_submit_cmd for commentary */ - ret = target_get_sess_cmd(se_sess, se_cmd, (flags & TARGET_SCF_ACK_KREF)); + ret = target_get_sess_cmd(se_cmd, flags & TARGET_SCF_ACK_KREF); if (ret) { core_tmr_release_req(se_cmd->se_tmr_req); return ret; @@ -2226,7 +2226,7 @@ static int transport_release_cmd(struct se_cmd *cmd) * If this cmd has been setup with target_get_sess_cmd(), drop * the kref and call ->release_cmd() in kref callback. */ - return target_put_sess_cmd(cmd->se_sess, cmd); + return target_put_sess_cmd(cmd); } /** @@ -2470,13 +2470,12 @@ int transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks) EXPORT_SYMBOL(transport_generic_free_cmd); /* target_get_sess_cmd - Add command to active ->sess_cmd_list - * @se_sess: session to reference * @se_cmd: command descriptor to add * @ack_kref: Signal that fabric will perform an ack target_put_sess_cmd() */ -int target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd, - bool ack_kref) +int target_get_sess_cmd(struct se_cmd *se_cmd, bool ack_kref) { + struct se_session *se_sess = se_cmd->se_sess; unsigned long flags; int ret = 0; @@ -2498,7 +2497,7 @@ out: spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); if (ret && ack_kref) - target_put_sess_cmd(se_sess, se_cmd); + target_put_sess_cmd(se_cmd); return ret; } @@ -2527,11 +2526,12 @@ static void target_release_cmd_kref(struct kref *kref) } /* target_put_sess_cmd - Check for active I/O shutdown via kref_put - * @se_sess: session to reference * @se_cmd: command descriptor to drop */ -int target_put_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd) +int target_put_sess_cmd(struct se_cmd *se_cmd) { + struct se_session *se_sess = se_cmd->se_sess; + if (!se_sess) { se_cmd->se_tfo->release_cmd(se_cmd); return 1; diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index ea32b386797f..636435b41293 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -607,7 +607,7 @@ static void vhost_scsi_free_cmd(struct vhost_scsi_cmd *cmd) static int vhost_scsi_check_stop_free(struct se_cmd *se_cmd) { - return target_put_sess_cmd(se_cmd->se_sess, se_cmd); + return target_put_sess_cmd(se_cmd); } static void diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index 0f4dc3768587..24c8d9d0d946 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -155,8 +155,8 @@ bool transport_wait_for_tasks(struct se_cmd *); int transport_check_aborted_status(struct se_cmd *, int); int transport_send_check_condition_and_sense(struct se_cmd *, sense_reason_t, int); -int target_get_sess_cmd(struct se_session *, struct se_cmd *, bool); -int target_put_sess_cmd(struct se_session *, struct se_cmd *); +int target_get_sess_cmd(struct se_cmd *, bool); +int target_put_sess_cmd(struct se_cmd *); void target_sess_cmd_list_set_waiting(struct se_session *); void target_wait_for_sess_cmds(struct se_session *); -- cgit v1.2.3-70-g09d2 From df75b956274b03e09426c1169f913d884d768ee7 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 13 Apr 2015 19:51:09 +0200 Subject: tcm_loop: remove struct tcm_loop_nacl Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/loopback/tcm_loop.c | 15 ++------------- drivers/target/loopback/tcm_loop.h | 4 ---- 2 files changed, 2 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index b863ce894977..e11bcf3e0889 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -706,25 +706,14 @@ static int tcm_loop_check_prot_fabric_only(struct se_portal_group *se_tpg) static struct se_node_acl *tcm_loop_tpg_alloc_fabric_acl( struct se_portal_group *se_tpg) { - struct tcm_loop_nacl *tl_nacl; - - tl_nacl = kzalloc(sizeof(struct tcm_loop_nacl), GFP_KERNEL); - if (!tl_nacl) { - pr_err("Unable to allocate struct tcm_loop_nacl\n"); - return NULL; - } - - return &tl_nacl->se_node_acl; + return kzalloc(sizeof(struct se_node_acl), GFP_KERNEL); } static void tcm_loop_tpg_release_fabric_acl( struct se_portal_group *se_tpg, struct se_node_acl *se_nacl) { - struct tcm_loop_nacl *tl_nacl = container_of(se_nacl, - struct tcm_loop_nacl, se_node_acl); - - kfree(tl_nacl); + kfree(se_nacl); } static u32 tcm_loop_get_inst_index(struct se_portal_group *se_tpg) diff --git a/drivers/target/loopback/tcm_loop.h b/drivers/target/loopback/tcm_loop.h index 433e595e5daa..4346462094a1 100644 --- a/drivers/target/loopback/tcm_loop.h +++ b/drivers/target/loopback/tcm_loop.h @@ -28,10 +28,6 @@ struct tcm_loop_nexus { struct se_session *se_sess; }; -struct tcm_loop_nacl { - struct se_node_acl se_node_acl; -}; - #define TCM_TRANSPORT_ONLINE 0 #define TCM_TRANSPORT_OFFLINE 1 -- cgit v1.2.3-70-g09d2 From a3b679e7e4369dfb5be735598888fcdef9d35196 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 13 Apr 2015 19:51:10 +0200 Subject: tcm_usb: remove struct usbg_nacl Except for the embedded struct se_node_acl none of the fields were ever used. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/usb/gadget/legacy/tcm_usb_gadget.c | 24 +++--------------------- drivers/usb/gadget/legacy/tcm_usb_gadget.h | 9 --------- 2 files changed, 3 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/legacy/tcm_usb_gadget.c b/drivers/usb/gadget/legacy/tcm_usb_gadget.c index 8b80addc4ce6..aba80e245e44 100644 --- a/drivers/usb/gadget/legacy/tcm_usb_gadget.c +++ b/drivers/usb/gadget/legacy/tcm_usb_gadget.c @@ -1380,22 +1380,14 @@ static char *usbg_parse_pr_out_transport_id( static struct se_node_acl *usbg_alloc_fabric_acl(struct se_portal_group *se_tpg) { - struct usbg_nacl *nacl; - - nacl = kzalloc(sizeof(struct usbg_nacl), GFP_KERNEL); - if (!nacl) - return NULL; - - return &nacl->se_node_acl; + return kzalloc(sizeof(struct se_node_acl), GFP_KERNEL); } static void usbg_release_fabric_acl( struct se_portal_group *se_tpg, struct se_node_acl *se_nacl) { - struct usbg_nacl *nacl = container_of(se_nacl, - struct usbg_nacl, se_node_acl); - kfree(nacl); + kfree(se_nacl); } static u32 usbg_tpg_get_inst_index(struct se_portal_group *se_tpg) @@ -1495,8 +1487,6 @@ static struct se_node_acl *usbg_make_nodeacl( const char *name) { struct se_node_acl *se_nacl, *se_nacl_new; - struct usbg_nacl *nacl; - u64 wwpn = 0; u32 nexus_depth; const char *wnn_name; @@ -1518,21 +1508,13 @@ static struct se_node_acl *usbg_make_nodeacl( usbg_release_fabric_acl(se_tpg, se_nacl_new); return se_nacl; } - /* - * Locate our struct usbg_nacl and set the FC Nport WWPN - */ - nacl = container_of(se_nacl, struct usbg_nacl, se_node_acl); - nacl->iport_wwpn = wwpn; - snprintf(nacl->iport_name, sizeof(nacl->iport_name), "%s", name); return se_nacl; } static void usbg_drop_nodeacl(struct se_node_acl *se_acl) { - struct usbg_nacl *nacl = container_of(se_acl, - struct usbg_nacl, se_node_acl); core_tpg_del_initiator_node_acl(se_acl->se_tpg, se_acl, 1); - kfree(nacl); + kfree(se_acl); } struct usbg_tpg *the_only_tpg_I_currently_have; diff --git a/drivers/usb/gadget/legacy/tcm_usb_gadget.h b/drivers/usb/gadget/legacy/tcm_usb_gadget.h index 8289219925b8..b254aec521da 100644 --- a/drivers/usb/gadget/legacy/tcm_usb_gadget.h +++ b/drivers/usb/gadget/legacy/tcm_usb_gadget.h @@ -25,15 +25,6 @@ enum { #define USB_G_ALT_INT_BBB 0 #define USB_G_ALT_INT_UAS 1 -struct usbg_nacl { - /* Binary World Wide unique Port Name for SAS Initiator port */ - u64 iport_wwpn; - /* ASCII formatted WWPN for Sas Initiator port */ - char iport_name[USBG_NAMELEN]; - /* Returned by usbg_make_nodeacl() */ - struct se_node_acl se_node_acl; -}; - struct tcm_usbg_nexus { struct se_session *tvn_se_sess; }; -- cgit v1.2.3-70-g09d2 From 16233799e383fc76f20d8142ef55da2308d36c65 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 13 Apr 2015 19:51:11 +0200 Subject: sbp_target: remove struct sbp_nacl Except for the embedded struct se_node_acl none of the fields were ever used. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/sbp/sbp_target.c | 24 +++--------------------- drivers/target/sbp/sbp_target.h | 9 --------- 2 files changed, 3 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index 18b0f9703ff2..61da83be8966 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -1714,24 +1714,14 @@ static u32 sbp_get_default_depth(struct se_portal_group *se_tpg) static struct se_node_acl *sbp_alloc_fabric_acl(struct se_portal_group *se_tpg) { - struct sbp_nacl *nacl; - - nacl = kzalloc(sizeof(struct sbp_nacl), GFP_KERNEL); - if (!nacl) { - pr_err("Unable to allocate struct sbp_nacl\n"); - return NULL; - } - - return &nacl->se_node_acl; + return kzalloc(sizeof(struct se_node_acl), GFP_KERNEL); } static void sbp_release_fabric_acl( struct se_portal_group *se_tpg, struct se_node_acl *se_nacl) { - struct sbp_nacl *nacl = - container_of(se_nacl, struct sbp_nacl, se_node_acl); - kfree(nacl); + kfree(se_nacl); } static u32 sbp_tpg_get_inst_index(struct se_portal_group *se_tpg) @@ -2106,7 +2096,6 @@ static struct se_node_acl *sbp_make_nodeacl( const char *name) { struct se_node_acl *se_nacl, *se_nacl_new; - struct sbp_nacl *nacl; u64 guid = 0; u32 nexus_depth = 1; @@ -2128,20 +2117,13 @@ static struct se_node_acl *sbp_make_nodeacl( return se_nacl; } - nacl = container_of(se_nacl, struct sbp_nacl, se_node_acl); - nacl->guid = guid; - sbp_format_wwn(nacl->iport_name, SBP_NAMELEN, guid); - return se_nacl; } static void sbp_drop_nodeacl(struct se_node_acl *se_acl) { - struct sbp_nacl *nacl = - container_of(se_acl, struct sbp_nacl, se_node_acl); - core_tpg_del_initiator_node_acl(se_acl->se_tpg, se_acl, 1); - kfree(nacl); + kfree(se_acl); } static int sbp_post_link_lun( diff --git a/drivers/target/sbp/sbp_target.h b/drivers/target/sbp/sbp_target.h index 6d0d74a2c545..e1b0b84f7379 100644 --- a/drivers/target/sbp/sbp_target.h +++ b/drivers/target/sbp/sbp_target.h @@ -151,15 +151,6 @@ struct sbp_session { u64 reconnect_expires; }; -struct sbp_nacl { - /* Initiator EUI-64 */ - u64 guid; - /* ASCII formatted GUID for SBP Initiator port */ - char iport_name[SBP_NAMELEN]; - /* Returned by sbp_make_nodeacl() */ - struct se_node_acl se_node_acl; -}; - struct sbp_tpg { /* Target portal group tag for TCM */ u16 tport_tpgt; -- cgit v1.2.3-70-g09d2 From 55570113a955091af5fafa94cd50914d994e09ae Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 13 Apr 2015 19:51:12 +0200 Subject: vhost/scsi: remove struct vhost_scsi_nacl Except for the embedded struct se_node_acl none of the fields were ever used. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/vhost/scsi.c | 34 +++------------------------------- 1 file changed, 3 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index 636435b41293..d21f2ba6c899 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -115,15 +115,6 @@ struct vhost_scsi_nexus { struct se_session *tvn_se_sess; }; -struct vhost_scsi_nacl { - /* Binary World Wide unique Port Name for Vhost Initiator port */ - u64 iport_wwpn; - /* ASCII formatted WWPN for Sas Initiator port */ - char iport_name[VHOST_SCSI_NAMELEN]; - /* Returned by vhost_scsi_make_nodeacl() */ - struct se_node_acl se_node_acl; -}; - struct vhost_scsi_tpg { /* Vhost port target portal group tag for TCM */ u16 tport_tpgt; @@ -442,24 +433,14 @@ static int vhost_scsi_check_prot_fabric_only(struct se_portal_group *se_tpg) static struct se_node_acl * vhost_scsi_alloc_fabric_acl(struct se_portal_group *se_tpg) { - struct vhost_scsi_nacl *nacl; - - nacl = kzalloc(sizeof(struct vhost_scsi_nacl), GFP_KERNEL); - if (!nacl) { - pr_err("Unable to allocate struct vhost_scsi_nacl\n"); - return NULL; - } - - return &nacl->se_node_acl; + return kzalloc(sizeof(struct se_node_acl), GFP_KERNEL); } static void vhost_scsi_release_fabric_acl(struct se_portal_group *se_tpg, struct se_node_acl *se_nacl) { - struct vhost_scsi_nacl *nacl = container_of(se_nacl, - struct vhost_scsi_nacl, se_node_acl); - kfree(nacl); + kfree(se_nacl); } static u32 vhost_scsi_tpg_get_inst_index(struct se_portal_group *se_tpg) @@ -1828,8 +1809,6 @@ vhost_scsi_make_nodeacl(struct se_portal_group *se_tpg, const char *name) { struct se_node_acl *se_nacl, *se_nacl_new; - struct vhost_scsi_nacl *nacl; - u64 wwpn = 0; u32 nexus_depth; /* vhost_scsi_parse_wwn(name, &wwpn, 1) < 0) @@ -1849,21 +1828,14 @@ vhost_scsi_make_nodeacl(struct se_portal_group *se_tpg, vhost_scsi_release_fabric_acl(se_tpg, se_nacl_new); return se_nacl; } - /* - * Locate our struct vhost_scsi_nacl and set the FC Nport WWPN - */ - nacl = container_of(se_nacl, struct vhost_scsi_nacl, se_node_acl); - nacl->iport_wwpn = wwpn; return se_nacl; } static void vhost_scsi_drop_nodeacl(struct se_node_acl *se_acl) { - struct vhost_scsi_nacl *nacl = container_of(se_acl, - struct vhost_scsi_nacl, se_node_acl); core_tpg_del_initiator_node_acl(se_acl->se_tpg, se_acl, 1); - kfree(nacl); + kfree(se_acl); } static void vhost_scsi_free_cmd_map_res(struct vhost_scsi_nexus *nexus, -- cgit v1.2.3-70-g09d2 From e1750d20e69477c0d7b26d6e0ba24c3c9ec47530 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 13 Apr 2015 19:51:13 +0200 Subject: target: make the tpg_get_default_depth method optional All fabric drivers except for iSCSI always return 1, so implement that as default behavior. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- Documentation/target/tcm_mod_builder.py | 8 -------- drivers/infiniband/ulp/srpt/ib_srpt.c | 6 ------ drivers/scsi/qla2xxx/tcm_qla2xxx.c | 7 ------- drivers/target/loopback/tcm_loop.c | 6 ------ drivers/target/sbp/sbp_target.c | 6 ------ drivers/target/target_core_configfs.c | 4 ---- drivers/target/target_core_tpg.c | 5 ++++- drivers/target/tcm_fc/tfc_conf.c | 6 ------ drivers/usb/gadget/legacy/tcm_usb_gadget.c | 6 ------ drivers/vhost/scsi.c | 6 ------ drivers/xen/xen-scsiback.c | 6 ------ 11 files changed, 4 insertions(+), 62 deletions(-) (limited to 'drivers') diff --git a/Documentation/target/tcm_mod_builder.py b/Documentation/target/tcm_mod_builder.py index 2ba71cea0172..3dab9b28f4f0 100755 --- a/Documentation/target/tcm_mod_builder.py +++ b/Documentation/target/tcm_mod_builder.py @@ -377,7 +377,6 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += " .get_fabric_proto_ident = " + fabric_mod_name + "_get_fabric_proto_ident,\n" buf += " .tpg_get_wwn = " + fabric_mod_name + "_get_fabric_wwn,\n" buf += " .tpg_get_tag = " + fabric_mod_name + "_get_tag,\n" - buf += " .tpg_get_default_depth = " + fabric_mod_name + "_get_default_depth,\n" buf += " .tpg_get_pr_transport_id = " + fabric_mod_name + "_get_pr_transport_id,\n" buf += " .tpg_get_pr_transport_id_len = " + fabric_mod_name + "_get_pr_transport_id_len,\n" buf += " .tpg_parse_pr_out_transport_id = " + fabric_mod_name + "_parse_pr_out_transport_id,\n" @@ -590,13 +589,6 @@ def tcm_mod_dump_fabric_ops(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += "}\n\n" bufi += "u16 " + fabric_mod_name + "_get_tag(struct se_portal_group *);\n" - if re.search('get_default_depth', fo): - buf += "u32 " + fabric_mod_name + "_get_default_depth(struct se_portal_group *se_tpg)\n" - buf += "{\n" - buf += " return 1;\n" - buf += "}\n\n" - bufi += "u32 " + fabric_mod_name + "_get_default_depth(struct se_portal_group *);\n" - if re.search('get_pr_transport_id\)\(', fo): buf += "u32 " + fabric_mod_name + "_get_pr_transport_id(\n" buf += " struct se_portal_group *se_tpg,\n" diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 6fbc7bc824d2..8198d4cb0694 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -3411,11 +3411,6 @@ static u16 srpt_get_tag(struct se_portal_group *tpg) return 1; } -static u32 srpt_get_default_depth(struct se_portal_group *se_tpg) -{ - return 1; -} - static u32 srpt_get_pr_transport_id(struct se_portal_group *se_tpg, struct se_node_acl *se_nacl, struct t10_pr_registration *pr_reg, @@ -3920,7 +3915,6 @@ static const struct target_core_fabric_ops srpt_template = { .get_fabric_proto_ident = srpt_get_fabric_proto_ident, .tpg_get_wwn = srpt_get_fabric_wwn, .tpg_get_tag = srpt_get_tag, - .tpg_get_default_depth = srpt_get_default_depth, .tpg_get_pr_transport_id = srpt_get_pr_transport_id, .tpg_get_pr_transport_id_len = srpt_get_pr_transport_id_len, .tpg_parse_pr_out_transport_id = srpt_parse_pr_out_transport_id, diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 8a6c87547303..5d69abcf9ed0 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -223,11 +223,6 @@ static u16 tcm_qla2xxx_get_tag(struct se_portal_group *se_tpg) return tpg->lport_tpgt; } -static u32 tcm_qla2xxx_get_default_depth(struct se_portal_group *se_tpg) -{ - return 1; -} - static u32 tcm_qla2xxx_get_pr_transport_id( struct se_portal_group *se_tpg, struct se_node_acl *se_nacl, @@ -1991,7 +1986,6 @@ static const struct target_core_fabric_ops tcm_qla2xxx_ops = { .get_fabric_proto_ident = tcm_qla2xxx_get_fabric_proto_ident, .tpg_get_wwn = tcm_qla2xxx_get_fabric_wwn, .tpg_get_tag = tcm_qla2xxx_get_tag, - .tpg_get_default_depth = tcm_qla2xxx_get_default_depth, .tpg_get_pr_transport_id = tcm_qla2xxx_get_pr_transport_id, .tpg_get_pr_transport_id_len = tcm_qla2xxx_get_pr_transport_id_len, .tpg_parse_pr_out_transport_id = tcm_qla2xxx_parse_pr_out_transport_id, @@ -2049,7 +2043,6 @@ static const struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = { .get_fabric_proto_ident = tcm_qla2xxx_get_fabric_proto_ident, .tpg_get_wwn = tcm_qla2xxx_get_fabric_wwn, .tpg_get_tag = tcm_qla2xxx_get_tag, - .tpg_get_default_depth = tcm_qla2xxx_get_default_depth, .tpg_get_pr_transport_id = tcm_qla2xxx_get_pr_transport_id, .tpg_get_pr_transport_id_len = tcm_qla2xxx_get_pr_transport_id_len, .tpg_parse_pr_out_transport_id = tcm_qla2xxx_parse_pr_out_transport_id, diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index e11bcf3e0889..12b85b03e9ae 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -566,11 +566,6 @@ static u16 tcm_loop_get_tag(struct se_portal_group *se_tpg) return tl_tpg->tl_tpgt; } -static u32 tcm_loop_get_default_depth(struct se_portal_group *se_tpg) -{ - return 1; -} - static u32 tcm_loop_get_pr_transport_id( struct se_portal_group *se_tpg, struct se_node_acl *se_nacl, @@ -1378,7 +1373,6 @@ static const struct target_core_fabric_ops loop_ops = { .get_fabric_proto_ident = tcm_loop_get_fabric_proto_ident, .tpg_get_wwn = tcm_loop_get_endpoint_wwn, .tpg_get_tag = tcm_loop_get_tag, - .tpg_get_default_depth = tcm_loop_get_default_depth, .tpg_get_pr_transport_id = tcm_loop_get_pr_transport_id, .tpg_get_pr_transport_id_len = tcm_loop_get_pr_transport_id_len, .tpg_parse_pr_out_transport_id = tcm_loop_parse_pr_out_transport_id, diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index 61da83be8966..0d70d4f58e43 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -1707,11 +1707,6 @@ static u16 sbp_get_tag(struct se_portal_group *se_tpg) return tpg->tport_tpgt; } -static u32 sbp_get_default_depth(struct se_portal_group *se_tpg) -{ - return 1; -} - static struct se_node_acl *sbp_alloc_fabric_acl(struct se_portal_group *se_tpg) { return kzalloc(sizeof(struct se_node_acl), GFP_KERNEL); @@ -2490,7 +2485,6 @@ static const struct target_core_fabric_ops sbp_ops = { .get_fabric_proto_ident = sbp_get_fabric_proto_ident, .tpg_get_wwn = sbp_get_fabric_wwn, .tpg_get_tag = sbp_get_tag, - .tpg_get_default_depth = sbp_get_default_depth, .tpg_get_pr_transport_id = sbp_get_pr_transport_id, .tpg_get_pr_transport_id_len = sbp_get_pr_transport_id_len, .tpg_parse_pr_out_transport_id = sbp_parse_pr_out_transport_id, diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index e7b0430a0575..c87ca0c50545 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -330,10 +330,6 @@ static int target_fabric_tf_ops_check(const struct target_core_fabric_ops *tfo) pr_err("Missing tfo->tpg_get_tag()\n"); return -EINVAL; } - if (!tfo->tpg_get_default_depth) { - pr_err("Missing tfo->tpg_get_default_depth()\n"); - return -EINVAL; - } if (!tfo->tpg_get_pr_transport_id) { pr_err("Missing tfo->tpg_get_pr_transport_id()\n"); return -EINVAL; diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index 47f064415bf6..5a9deb2b24af 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -282,7 +282,10 @@ struct se_node_acl *core_tpg_check_initiator_node_acl( spin_lock_init(&acl->device_list_lock); spin_lock_init(&acl->nacl_sess_lock); atomic_set(&acl->acl_pr_ref_count, 0); - acl->queue_depth = tpg->se_tpg_tfo->tpg_get_default_depth(tpg); + if (tpg->se_tpg_tfo->tpg_get_default_depth) + acl->queue_depth = tpg->se_tpg_tfo->tpg_get_default_depth(tpg); + else + acl->queue_depth = 1; snprintf(acl->initiatorname, TRANSPORT_IQN_LEN, "%s", initiatorname); acl->se_tpg = tpg; acl->acl_index = scsi_get_new_index(SCSI_AUTH_INTR_INDEX); diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c index 65dce1345966..46b4387460e5 100644 --- a/drivers/target/tcm_fc/tfc_conf.c +++ b/drivers/target/tcm_fc/tfc_conf.c @@ -486,11 +486,6 @@ static u16 ft_get_tag(struct se_portal_group *se_tpg) return tpg->index; } -static u32 ft_get_default_depth(struct se_portal_group *se_tpg) -{ - return 1; -} - static int ft_check_false(struct se_portal_group *se_tpg) { return 0; @@ -514,7 +509,6 @@ static const struct target_core_fabric_ops ft_fabric_ops = { .get_fabric_proto_ident = fc_get_fabric_proto_ident, .tpg_get_wwn = ft_get_fabric_wwn, .tpg_get_tag = ft_get_tag, - .tpg_get_default_depth = ft_get_default_depth, .tpg_get_pr_transport_id = fc_get_pr_transport_id, .tpg_get_pr_transport_id_len = fc_get_pr_transport_id_len, .tpg_parse_pr_out_transport_id = fc_parse_pr_out_transport_id, diff --git a/drivers/usb/gadget/legacy/tcm_usb_gadget.c b/drivers/usb/gadget/legacy/tcm_usb_gadget.c index aba80e245e44..b7a78f72fb0e 100644 --- a/drivers/usb/gadget/legacy/tcm_usb_gadget.c +++ b/drivers/usb/gadget/legacy/tcm_usb_gadget.c @@ -1307,11 +1307,6 @@ static u16 usbg_get_tag(struct se_portal_group *se_tpg) return tpg->tport_tpgt; } -static u32 usbg_get_default_depth(struct se_portal_group *se_tpg) -{ - return 1; -} - static u32 usbg_get_pr_transport_id( struct se_portal_group *se_tpg, struct se_node_acl *se_nacl, @@ -1852,7 +1847,6 @@ static const struct target_core_fabric_ops usbg_ops = { .get_fabric_proto_ident = usbg_get_fabric_proto_ident, .tpg_get_wwn = usbg_get_fabric_wwn, .tpg_get_tag = usbg_get_tag, - .tpg_get_default_depth = usbg_get_default_depth, .tpg_get_pr_transport_id = usbg_get_pr_transport_id, .tpg_get_pr_transport_id_len = usbg_get_pr_transport_id_len, .tpg_parse_pr_out_transport_id = usbg_parse_pr_out_transport_id, diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index d21f2ba6c899..fb8a93d5bfba 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -326,11 +326,6 @@ static u16 vhost_scsi_get_tpgt(struct se_portal_group *se_tpg) return tpg->tport_tpgt; } -static u32 vhost_scsi_get_default_depth(struct se_portal_group *se_tpg) -{ - return 1; -} - static u32 vhost_scsi_get_pr_transport_id(struct se_portal_group *se_tpg, struct se_node_acl *se_nacl, @@ -2300,7 +2295,6 @@ static struct target_core_fabric_ops vhost_scsi_ops = { .get_fabric_proto_ident = vhost_scsi_get_fabric_proto_ident, .tpg_get_wwn = vhost_scsi_get_fabric_wwn, .tpg_get_tag = vhost_scsi_get_tpgt, - .tpg_get_default_depth = vhost_scsi_get_default_depth, .tpg_get_pr_transport_id = vhost_scsi_get_pr_transport_id, .tpg_get_pr_transport_id_len = vhost_scsi_get_pr_transport_id_len, .tpg_parse_pr_out_transport_id = vhost_scsi_parse_pr_out_transport_id, diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index b7f51504f85a..c0d4aee0eeb5 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -1292,11 +1292,6 @@ static u16 scsiback_get_tag(struct se_portal_group *se_tpg) return tpg->tport_tpgt; } -static u32 scsiback_get_default_depth(struct se_portal_group *se_tpg) -{ - return 1; -} - static u32 scsiback_get_pr_transport_id(struct se_portal_group *se_tpg, struct se_node_acl *se_nacl, @@ -1950,7 +1945,6 @@ static const struct target_core_fabric_ops scsiback_ops = { .get_fabric_proto_ident = scsiback_get_fabric_proto_ident, .tpg_get_wwn = scsiback_get_fabric_wwn, .tpg_get_tag = scsiback_get_tag, - .tpg_get_default_depth = scsiback_get_default_depth, .tpg_get_pr_transport_id = scsiback_get_pr_transport_id, .tpg_get_pr_transport_id_len = scsiback_get_pr_transport_id_len, .tpg_parse_pr_out_transport_id = scsiback_parse_pr_out_transport_id, -- cgit v1.2.3-70-g09d2 From c7d6a803926bae9bbf4510a18fc8dd8957cc0e01 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 13 Apr 2015 19:51:14 +0200 Subject: target: refactor init/drop_nodeacl methods By always allocating and adding, respectively removing and freeing the se_node_acl structure in core code we can remove tons of repeated code in the init_nodeacl and drop_nodeacl routines. Additionally this now respects the get_default_queue_depth method in this code path as well. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- Documentation/target/tcm_mod_builder.py | 77 ---------------------------- Documentation/target/tcm_mod_builder.txt | 4 +- drivers/infiniband/ulp/srpt/ib_srpt.c | 58 +++++---------------- drivers/scsi/qla2xxx/tcm_qla2xxx.c | 59 +++------------------ drivers/target/iscsi/iscsi_target_configfs.c | 49 ++++-------------- drivers/target/sbp/sbp_target.c | 36 ++----------- drivers/target/target_core_fabric_configfs.c | 22 ++++---- drivers/target/target_core_internal.h | 3 ++ drivers/target/target_core_tpg.c | 46 ++++------------- drivers/target/tcm_fc/tfc_conf.c | 48 +++-------------- drivers/usb/gadget/legacy/tcm_usb_gadget.c | 42 ++------------- drivers/vhost/scsi.c | 39 -------------- drivers/xen/xen-scsiback.c | 6 --- include/target/target_core_fabric.h | 9 +--- 14 files changed, 77 insertions(+), 421 deletions(-) (limited to 'drivers') diff --git a/Documentation/target/tcm_mod_builder.py b/Documentation/target/tcm_mod_builder.py index 3dab9b28f4f0..3e54809b3aa1 100755 --- a/Documentation/target/tcm_mod_builder.py +++ b/Documentation/target/tcm_mod_builder.py @@ -50,15 +50,6 @@ def tcm_mod_build_FC_include(fabric_mod_dir_var, fabric_mod_name): buf = "#define " + fabric_mod_name.upper() + "_VERSION \"v0.1\"\n" buf += "#define " + fabric_mod_name.upper() + "_NAMELEN 32\n" buf += "\n" - buf += "struct " + fabric_mod_name + "_nacl {\n" - buf += " /* Binary World Wide unique Port Name for FC Initiator Nport */\n" - buf += " u64 nport_wwpn;\n" - buf += " /* ASCII formatted WWPN for FC Initiator Nport */\n" - buf += " char nport_name[" + fabric_mod_name.upper() + "_NAMELEN];\n" - buf += " /* Returned by " + fabric_mod_name + "_make_nodeacl() */\n" - buf += " struct se_node_acl se_node_acl;\n" - buf += "};\n" - buf += "\n" buf += "struct " + fabric_mod_name + "_tpg {\n" buf += " /* FC lport target portal group tag for TCM */\n" buf += " u16 lport_tpgt;\n" @@ -105,14 +96,6 @@ def tcm_mod_build_SAS_include(fabric_mod_dir_var, fabric_mod_name): buf = "#define " + fabric_mod_name.upper() + "_VERSION \"v0.1\"\n" buf += "#define " + fabric_mod_name.upper() + "_NAMELEN 32\n" buf += "\n" - buf += "struct " + fabric_mod_name + "_nacl {\n" - buf += " /* Binary World Wide unique Port Name for SAS Initiator port */\n" - buf += " u64 iport_wwpn;\n" - buf += " /* ASCII formatted WWPN for Sas Initiator port */\n" - buf += " char iport_name[" + fabric_mod_name.upper() + "_NAMELEN];\n" - buf += " /* Returned by " + fabric_mod_name + "_make_nodeacl() */\n" - buf += " struct se_node_acl se_node_acl;\n" - buf += "};\n\n" buf += "struct " + fabric_mod_name + "_tpg {\n" buf += " /* SAS port target portal group tag for TCM */\n" buf += " u16 tport_tpgt;\n" @@ -158,12 +141,6 @@ def tcm_mod_build_iSCSI_include(fabric_mod_dir_var, fabric_mod_name): buf = "#define " + fabric_mod_name.upper() + "_VERSION \"v0.1\"\n" buf += "#define " + fabric_mod_name.upper() + "_NAMELEN 32\n" buf += "\n" - buf += "struct " + fabric_mod_name + "_nacl {\n" - buf += " /* ASCII formatted InitiatorName */\n" - buf += " char iport_name[" + fabric_mod_name.upper() + "_NAMELEN];\n" - buf += " /* Returned by " + fabric_mod_name + "_make_nodeacl() */\n" - buf += " struct se_node_acl se_node_acl;\n" - buf += "};\n\n" buf += "struct " + fabric_mod_name + "_tpg {\n" buf += " /* iSCSI target portal group tag for TCM */\n" buf += " u16 tport_tpgt;\n" @@ -239,54 +216,6 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += "static const struct target_core_fabric_ops " + fabric_mod_name + "_ops;\n\n" - buf += "static struct se_node_acl *" + fabric_mod_name + "_make_nodeacl(\n" - buf += " struct se_portal_group *se_tpg,\n" - buf += " struct config_group *group,\n" - buf += " const char *name)\n" - buf += "{\n" - buf += " struct se_node_acl *se_nacl, *se_nacl_new;\n" - buf += " struct " + fabric_mod_name + "_nacl *nacl;\n" - - if proto_ident == "FC" or proto_ident == "SAS": - buf += " u64 wwpn = 0;\n" - - buf += " u32 nexus_depth;\n\n" - buf += " /* " + fabric_mod_name + "_parse_wwn(name, &wwpn, 1) < 0)\n" - buf += " return ERR_PTR(-EINVAL); */\n" - buf += " se_nacl_new = " + fabric_mod_name + "_alloc_fabric_acl(se_tpg);\n" - buf += " if (!se_nacl_new)\n" - buf += " return ERR_PTR(-ENOMEM);\n" - buf += "//#warning FIXME: Hardcoded nexus depth in " + fabric_mod_name + "_make_nodeacl()\n" - buf += " nexus_depth = 1;\n" - buf += " /*\n" - buf += " * se_nacl_new may be released by core_tpg_add_initiator_node_acl()\n" - buf += " * when converting a NodeACL from demo mode -> explict\n" - buf += " */\n" - buf += " se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new,\n" - buf += " name, nexus_depth);\n" - buf += " if (IS_ERR(se_nacl)) {\n" - buf += " " + fabric_mod_name + "_release_fabric_acl(se_tpg, se_nacl_new);\n" - buf += " return se_nacl;\n" - buf += " }\n" - buf += " /*\n" - buf += " * Locate our struct " + fabric_mod_name + "_nacl and set the FC Nport WWPN\n" - buf += " */\n" - buf += " nacl = container_of(se_nacl, struct " + fabric_mod_name + "_nacl, se_node_acl);\n" - - if proto_ident == "FC" or proto_ident == "SAS": - buf += " nacl->" + fabric_mod_init_port + "_wwpn = wwpn;\n" - - buf += " /* " + fabric_mod_name + "_format_wwn(&nacl->" + fabric_mod_init_port + "_name[0], " + fabric_mod_name.upper() + "_NAMELEN, wwpn); */\n\n" - buf += " return se_nacl;\n" - buf += "}\n\n" - buf += "static void " + fabric_mod_name + "_drop_nodeacl(struct se_node_acl *se_acl)\n" - buf += "{\n" - buf += " struct " + fabric_mod_name + "_nacl *nacl = container_of(se_acl,\n" - buf += " struct " + fabric_mod_name + "_nacl, se_node_acl);\n" - buf += " core_tpg_del_initiator_node_acl(se_acl->se_tpg, se_acl, 1);\n" - buf += " kfree(nacl);\n" - buf += "}\n\n" - buf += "static struct se_portal_group *" + fabric_mod_name + "_make_tpg(\n" buf += " struct se_wwn *wwn,\n" buf += " struct config_group *group,\n" @@ -408,12 +337,6 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += " .fabric_drop_wwn = " + fabric_mod_name + "_drop_" + fabric_mod_port + ",\n" buf += " .fabric_make_tpg = " + fabric_mod_name + "_make_tpg,\n" buf += " .fabric_drop_tpg = " + fabric_mod_name + "_drop_tpg,\n" - buf += " .fabric_post_link = NULL,\n" - buf += " .fabric_pre_unlink = NULL,\n" - buf += " .fabric_make_np = NULL,\n" - buf += " .fabric_drop_np = NULL,\n" - buf += " .fabric_make_nodeacl = " + fabric_mod_name + "_make_nodeacl,\n" - buf += " .fabric_drop_nodeacl = " + fabric_mod_name + "_drop_nodeacl,\n" buf += "\n" buf += " .tfc_wwn_attrs = " + fabric_mod_name + "_wwn_attrs;\n" buf += "};\n\n" diff --git a/Documentation/target/tcm_mod_builder.txt b/Documentation/target/tcm_mod_builder.txt index 84533d8e747f..ae22f7005540 100644 --- a/Documentation/target/tcm_mod_builder.txt +++ b/Documentation/target/tcm_mod_builder.txt @@ -13,8 +13,8 @@ fabric skeleton, by simply using: This script will create a new drivers/target/$TCM_NEW_MOD/, and will do the following *) Generate new API callers for drivers/target/target_core_fabric_configs.c logic - ->make_nodeacl(), ->drop_nodeacl(), ->make_tpg(), ->drop_tpg() - ->make_wwn(), ->drop_wwn(). These are created into $TCM_NEW_MOD/$TCM_NEW_MOD_configfs.c + ->make_tpg(), ->drop_tpg(), ->make_wwn(), ->drop_wwn(). These are created + into $TCM_NEW_MOD/$TCM_NEW_MOD_configfs.c *) Generate basic infrastructure for loading/unloading LKMs and TCM/ConfigFS fabric module using a skeleton struct target_core_fabric_ops API template. *) Based on user defined T10 Proto_Ident for the new fabric module being built, diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 8198d4cb0694..c1f3aa52f42b 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -3592,40 +3592,19 @@ out: * configfs callback function invoked for * mkdir /sys/kernel/config/target/$driver/$port/$tpg/acls/$i_port_id */ -static struct se_node_acl *srpt_make_nodeacl(struct se_portal_group *tpg, - struct config_group *group, - const char *name) +static int srpt_init_nodeacl(struct se_node_acl *se_nacl, const char *name) { - struct srpt_port *sport = container_of(tpg, struct srpt_port, port_tpg_1); - struct se_node_acl *se_nacl, *se_nacl_new; - struct srpt_node_acl *nacl; - int ret = 0; - u32 nexus_depth = 1; + struct srpt_port *sport = + container_of(se_nacl->se_tpg, struct srpt_port, port_tpg_1); + struct srpt_node_acl *nacl = + container_of(se_nacl, struct srpt_node_acl, nacl); u8 i_port_id[16]; if (srpt_parse_i_port_id(i_port_id, name) < 0) { pr_err("invalid initiator port ID %s\n", name); - ret = -EINVAL; - goto err; + return -EINVAL; } - se_nacl_new = srpt_alloc_fabric_acl(tpg); - if (!se_nacl_new) { - ret = -ENOMEM; - goto err; - } - /* - * nacl_new may be released by core_tpg_add_initiator_node_acl() - * when converting a node ACL from demo mode to explict - */ - se_nacl = core_tpg_add_initiator_node_acl(tpg, se_nacl_new, name, - nexus_depth); - if (IS_ERR(se_nacl)) { - ret = PTR_ERR(se_nacl); - goto err; - } - /* Locate our struct srpt_node_acl and set sdev and i_port_id. */ - nacl = container_of(se_nacl, struct srpt_node_acl, nacl); memcpy(&nacl->i_port_id[0], &i_port_id[0], 16); nacl->sport = sport; @@ -3633,29 +3612,22 @@ static struct se_node_acl *srpt_make_nodeacl(struct se_portal_group *tpg, list_add_tail(&nacl->list, &sport->port_acl_list); spin_unlock_irq(&sport->port_acl_lock); - return se_nacl; -err: - return ERR_PTR(ret); + return 0; } /* * configfs callback function invoked for * rmdir /sys/kernel/config/target/$driver/$port/$tpg/acls/$i_port_id */ -static void srpt_drop_nodeacl(struct se_node_acl *se_nacl) +static void srpt_cleanup_nodeacl(struct se_node_acl *se_nacl) { - struct srpt_node_acl *nacl; - struct srpt_device *sdev; - struct srpt_port *sport; + struct srpt_node_acl *nacl = + container_of(se_nacl, struct srpt_node_acl, nacl); + struct srpt_port *sport = nacl->sport; - nacl = container_of(se_nacl, struct srpt_node_acl, nacl); - sport = nacl->sport; - sdev = sport->sdev; spin_lock_irq(&sport->port_acl_lock); list_del(&nacl->list); spin_unlock_irq(&sport->port_acl_lock); - core_tpg_del_initiator_node_acl(&sport->port_tpg_1, se_nacl, 1); - srpt_release_fabric_acl(NULL, se_nacl); } static ssize_t srpt_tpg_attrib_show_srp_max_rdma_size( @@ -3948,12 +3920,8 @@ static const struct target_core_fabric_ops srpt_template = { .fabric_drop_wwn = srpt_drop_tport, .fabric_make_tpg = srpt_make_tpg, .fabric_drop_tpg = srpt_drop_tpg, - .fabric_post_link = NULL, - .fabric_pre_unlink = NULL, - .fabric_make_np = NULL, - .fabric_drop_np = NULL, - .fabric_make_nodeacl = srpt_make_nodeacl, - .fabric_drop_nodeacl = srpt_drop_nodeacl, + .fabric_init_nodeacl = srpt_init_nodeacl, + .fabric_cleanup_nodeacl = srpt_cleanup_nodeacl, .tfc_wwn_attrs = srpt_wwn_attrs, .tfc_tpg_base_attrs = srpt_tpg_attrs, diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 5d69abcf9ed0..a7ab689f5524 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -847,53 +847,20 @@ static void tcm_qla2xxx_shutdown_sess(struct qla_tgt_sess *sess) target_sess_cmd_list_set_waiting(sess->se_sess); } -static struct se_node_acl *tcm_qla2xxx_make_nodeacl( - struct se_portal_group *se_tpg, - struct config_group *group, - const char *name) +static int tcm_qla2xxx_init_nodeacl(struct se_node_acl *se_nacl, + const char *name) { - struct se_node_acl *se_nacl, *se_nacl_new; - struct tcm_qla2xxx_nacl *nacl; + struct tcm_qla2xxx_nacl *nacl = + container_of(se_nacl, struct tcm_qla2xxx_nacl, se_node_acl); u64 wwnn; - u32 qla2xxx_nexus_depth; if (tcm_qla2xxx_parse_wwn(name, &wwnn, 1) < 0) - return ERR_PTR(-EINVAL); - - se_nacl_new = tcm_qla2xxx_alloc_fabric_acl(se_tpg); - if (!se_nacl_new) - return ERR_PTR(-ENOMEM); -/* #warning FIXME: Hardcoded qla2xxx_nexus depth in tcm_qla2xxx_make_nodeacl */ - qla2xxx_nexus_depth = 1; + return -EINVAL; - /* - * se_nacl_new may be released by core_tpg_add_initiator_node_acl() - * when converting a NodeACL from demo mode -> explict - */ - se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new, - name, qla2xxx_nexus_depth); - if (IS_ERR(se_nacl)) { - tcm_qla2xxx_release_fabric_acl(se_tpg, se_nacl_new); - return se_nacl; - } - /* - * Locate our struct tcm_qla2xxx_nacl and set the FC Nport WWPN - */ - nacl = container_of(se_nacl, struct tcm_qla2xxx_nacl, se_node_acl); nacl->nport_wwnn = wwnn; tcm_qla2xxx_format_wwn(&nacl->nport_name[0], TCM_QLA2XXX_NAMELEN, wwnn); - return se_nacl; -} - -static void tcm_qla2xxx_drop_nodeacl(struct se_node_acl *se_acl) -{ - struct se_portal_group *se_tpg = se_acl->se_tpg; - struct tcm_qla2xxx_nacl *nacl = container_of(se_acl, - struct tcm_qla2xxx_nacl, se_node_acl); - - core_tpg_del_initiator_node_acl(se_tpg, se_acl, 1); - kfree(nacl); + return 0; } /* Start items for tcm_qla2xxx_tpg_attrib_cit */ @@ -2024,12 +1991,7 @@ static const struct target_core_fabric_ops tcm_qla2xxx_ops = { .fabric_drop_wwn = tcm_qla2xxx_drop_lport, .fabric_make_tpg = tcm_qla2xxx_make_tpg, .fabric_drop_tpg = tcm_qla2xxx_drop_tpg, - .fabric_post_link = NULL, - .fabric_pre_unlink = NULL, - .fabric_make_np = NULL, - .fabric_drop_np = NULL, - .fabric_make_nodeacl = tcm_qla2xxx_make_nodeacl, - .fabric_drop_nodeacl = tcm_qla2xxx_drop_nodeacl, + .fabric_init_nodeacl = tcm_qla2xxx_init_nodeacl, .tfc_wwn_attrs = tcm_qla2xxx_wwn_attrs, .tfc_tpg_base_attrs = tcm_qla2xxx_tpg_attrs, @@ -2079,12 +2041,7 @@ static const struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = { .fabric_drop_wwn = tcm_qla2xxx_npiv_drop_lport, .fabric_make_tpg = tcm_qla2xxx_npiv_make_tpg, .fabric_drop_tpg = tcm_qla2xxx_drop_tpg, - .fabric_post_link = NULL, - .fabric_pre_unlink = NULL, - .fabric_make_np = NULL, - .fabric_drop_np = NULL, - .fabric_make_nodeacl = tcm_qla2xxx_make_nodeacl, - .fabric_drop_nodeacl = tcm_qla2xxx_drop_nodeacl, + .fabric_init_nodeacl = tcm_qla2xxx_init_nodeacl, .tfc_wwn_attrs = tcm_qla2xxx_wwn_attrs, .tfc_tpg_base_attrs = tcm_qla2xxx_npiv_tpg_attrs, diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 568e478615a5..7d9ff8cbbb5d 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -874,43 +874,19 @@ static struct se_node_acl *lio_tpg_alloc_fabric_acl( return &acl->se_node_acl; } -static struct se_node_acl *lio_target_make_nodeacl( - struct se_portal_group *se_tpg, - struct config_group *group, - const char *name) +static int lio_target_init_nodeacl(struct se_node_acl *se_nacl, + const char *name) { - struct config_group *stats_cg; - struct iscsi_node_acl *acl; - struct se_node_acl *se_nacl_new, *se_nacl; - struct iscsi_portal_group *tpg = container_of(se_tpg, - struct iscsi_portal_group, tpg_se_tpg); - u32 cmdsn_depth; - - se_nacl_new = lio_tpg_alloc_fabric_acl(se_tpg); - if (!se_nacl_new) - return ERR_PTR(-ENOMEM); - - cmdsn_depth = tpg->tpg_attrib.default_cmdsn_depth; - /* - * se_nacl_new may be released by core_tpg_add_initiator_node_acl() - * when converting a NdoeACL from demo mode -> explict - */ - se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new, - name, cmdsn_depth); - if (IS_ERR(se_nacl)) - return se_nacl; - - acl = container_of(se_nacl, struct iscsi_node_acl, se_node_acl); - stats_cg = &se_nacl->acl_fabric_stat_group; + struct iscsi_node_acl *acl = + container_of(se_nacl, struct iscsi_node_acl, se_node_acl); + struct config_group *stats_cg = &se_nacl->acl_fabric_stat_group; stats_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2, GFP_KERNEL); if (!stats_cg->default_groups) { pr_err("Unable to allocate memory for" " stats_cg->default_groups\n"); - core_tpg_del_initiator_node_acl(se_tpg, se_nacl, 1); - kfree(acl); - return ERR_PTR(-ENOMEM); + return -ENOMEM; } stats_cg->default_groups[0] = &acl->node_stat_grps.iscsi_sess_stats_group; @@ -918,13 +894,11 @@ static struct se_node_acl *lio_target_make_nodeacl( config_group_init_type_name(&acl->node_stat_grps.iscsi_sess_stats_group, "iscsi_sess_stats", &iscsi_stat_sess_cit); - return se_nacl; + return 0; } -static void lio_target_drop_nodeacl( - struct se_node_acl *se_nacl) +static void lio_target_cleanup_nodeacl( struct se_node_acl *se_nacl) { - struct se_portal_group *se_tpg = se_nacl->se_tpg; struct iscsi_node_acl *acl = container_of(se_nacl, struct iscsi_node_acl, se_node_acl); struct config_item *df_item; @@ -938,9 +912,6 @@ static void lio_target_drop_nodeacl( config_item_put(df_item); } kfree(stats_cg->default_groups); - - core_tpg_del_initiator_node_acl(se_tpg, se_nacl, 1); - kfree(acl); } /* End items for lio_target_acl_cit */ @@ -2020,8 +1991,8 @@ const struct target_core_fabric_ops iscsi_ops = { .fabric_drop_tpg = lio_target_tiqn_deltpg, .fabric_make_np = lio_target_call_addnptotpg, .fabric_drop_np = lio_target_call_delnpfromtpg, - .fabric_make_nodeacl = lio_target_make_nodeacl, - .fabric_drop_nodeacl = lio_target_drop_nodeacl, + .fabric_init_nodeacl = lio_target_init_nodeacl, + .fabric_cleanup_nodeacl = lio_target_cleanup_nodeacl, .tfc_discovery_attrs = lio_target_discovery_auth_attrs, .tfc_wwn_attrs = lio_target_wwn_attrs, diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index 0d70d4f58e43..3a47fe46fbca 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -2085,40 +2085,13 @@ static ssize_t sbp_format_wwn(char *buf, size_t len, u64 wwn) return snprintf(buf, len, "%016llx", wwn); } -static struct se_node_acl *sbp_make_nodeacl( - struct se_portal_group *se_tpg, - struct config_group *group, - const char *name) +static int sbp_init_nodeacl(struct se_node_acl *se_nacl, const char *name) { - struct se_node_acl *se_nacl, *se_nacl_new; u64 guid = 0; - u32 nexus_depth = 1; if (sbp_parse_wwn(name, &guid) < 0) - return ERR_PTR(-EINVAL); - - se_nacl_new = sbp_alloc_fabric_acl(se_tpg); - if (!se_nacl_new) - return ERR_PTR(-ENOMEM); - - /* - * se_nacl_new may be released by core_tpg_add_initiator_node_acl() - * when converting a NodeACL from demo mode -> explict - */ - se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new, - name, nexus_depth); - if (IS_ERR(se_nacl)) { - sbp_release_fabric_acl(se_tpg, se_nacl_new); - return se_nacl; - } - - return se_nacl; -} - -static void sbp_drop_nodeacl(struct se_node_acl *se_acl) -{ - core_tpg_del_initiator_node_acl(se_acl->se_tpg, se_acl, 1); - kfree(se_acl); + return -EINVAL; + return 0; } static int sbp_post_link_lun( @@ -2518,8 +2491,7 @@ static const struct target_core_fabric_ops sbp_ops = { .fabric_pre_unlink = sbp_pre_unlink_lun, .fabric_make_np = NULL, .fabric_drop_np = NULL, - .fabric_make_nodeacl = sbp_make_nodeacl, - .fabric_drop_nodeacl = sbp_drop_nodeacl, + .fabric_init_nodeacl = sbp_init_nodeacl, .tfc_wwn_attrs = sbp_wwn_attrs, .tfc_tpg_base_attrs = sbp_tpg_base_attrs, diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index 1f7886bb16bf..f4d9467c3e14 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -458,10 +458,11 @@ static void target_fabric_nacl_base_release(struct config_item *item) { struct se_node_acl *se_nacl = container_of(to_config_group(item), struct se_node_acl, acl_group); - struct se_portal_group *se_tpg = se_nacl->se_tpg; - struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; + struct target_fabric_configfs *tf = se_nacl->se_tpg->se_tpg_wwn->wwn_tf; - tf->tf_ops.fabric_drop_nodeacl(se_nacl); + if (tf->tf_ops.fabric_cleanup_nodeacl) + tf->tf_ops.fabric_cleanup_nodeacl(se_nacl); + core_tpg_del_initiator_node_acl(se_nacl); } static struct configfs_item_operations target_fabric_nacl_base_item_ops = { @@ -501,15 +502,18 @@ static struct config_group *target_fabric_make_nodeacl( struct se_node_acl *se_nacl; struct config_group *nacl_cg; - if (!tf->tf_ops.fabric_make_nodeacl) { - pr_err("tf->tf_ops.fabric_make_nodeacl is NULL\n"); - return ERR_PTR(-ENOSYS); - } - - se_nacl = tf->tf_ops.fabric_make_nodeacl(se_tpg, group, name); + se_nacl = core_tpg_add_initiator_node_acl(se_tpg, name); if (IS_ERR(se_nacl)) return ERR_CAST(se_nacl); + if (tf->tf_ops.fabric_init_nodeacl) { + int ret = tf->tf_ops.fabric_init_nodeacl(se_nacl, name); + if (ret) { + core_tpg_del_initiator_node_acl(se_nacl); + return ERR_PTR(ret); + } + } + nacl_cg = &se_nacl->acl_group; nacl_cg->default_groups = se_nacl->acl_default_groups; nacl_cg->default_groups[0] = &se_nacl->acl_attrib_group; diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index 75338c348be4..058ca71cda81 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -59,6 +59,9 @@ struct se_lun *core_tpg_alloc_lun(struct se_portal_group *, u32); int core_tpg_add_lun(struct se_portal_group *, struct se_lun *, u32, struct se_device *); void core_tpg_remove_lun(struct se_portal_group *, struct se_lun *); +struct se_node_acl *core_tpg_add_initiator_node_acl(struct se_portal_group *tpg, + const char *initiatorname); +void core_tpg_del_initiator_node_acl(struct se_node_acl *acl); /* target_core_transport.c */ extern struct kmem_cache *se_tmr_req_cache; diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index 5a9deb2b24af..78dd53ada04a 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -353,17 +353,11 @@ void core_tpg_clear_object_luns(struct se_portal_group *tpg) } EXPORT_SYMBOL(core_tpg_clear_object_luns); -/* core_tpg_add_initiator_node_acl(): - * - * - */ struct se_node_acl *core_tpg_add_initiator_node_acl( struct se_portal_group *tpg, - struct se_node_acl *se_nacl, - const char *initiatorname, - u32 queue_depth) + const char *initiatorname) { - struct se_node_acl *acl = NULL; + struct se_node_acl *acl; spin_lock_irq(&tpg->acl_node_lock); acl = __core_tpg_get_initiator_node_acl(tpg, initiatorname); @@ -374,14 +368,6 @@ struct se_node_acl *core_tpg_add_initiator_node_acl( " for %s\n", tpg->se_tpg_tfo->get_fabric_name(), tpg->se_tpg_tfo->tpg_get_tag(tpg), initiatorname); spin_unlock_irq(&tpg->acl_node_lock); - /* - * Release the locally allocated struct se_node_acl - * because * core_tpg_add_initiator_node_acl() returned - * a pointer to an existing demo mode node ACL. - */ - if (se_nacl) - tpg->se_tpg_tfo->tpg_release_fabric_acl(tpg, - se_nacl); goto done; } @@ -394,16 +380,11 @@ struct se_node_acl *core_tpg_add_initiator_node_acl( } spin_unlock_irq(&tpg->acl_node_lock); - if (!se_nacl) { + acl = tpg->se_tpg_tfo->tpg_alloc_fabric_acl(tpg); + if (!acl) { pr_err("struct se_node_acl pointer is NULL\n"); return ERR_PTR(-EINVAL); } - /* - * For v4.x logic the se_node_acl_s is hanging off a fabric - * dependent structure allocated via - * struct target_core_fabric_ops->fabric_make_nodeacl() - */ - acl = se_nacl; INIT_LIST_HEAD(&acl->acl_list); INIT_LIST_HEAD(&acl->acl_sess_list); @@ -412,7 +393,10 @@ struct se_node_acl *core_tpg_add_initiator_node_acl( spin_lock_init(&acl->device_list_lock); spin_lock_init(&acl->nacl_sess_lock); atomic_set(&acl->acl_pr_ref_count, 0); - acl->queue_depth = queue_depth; + if (tpg->se_tpg_tfo->tpg_get_default_depth) + acl->queue_depth = tpg->se_tpg_tfo->tpg_get_default_depth(tpg); + else + acl->queue_depth = 1; snprintf(acl->initiatorname, TRANSPORT_IQN_LEN, "%s", initiatorname); acl->se_tpg = tpg; acl->acl_index = scsi_get_new_index(SCSI_AUTH_INTR_INDEX); @@ -443,17 +427,10 @@ done: return acl; } -EXPORT_SYMBOL(core_tpg_add_initiator_node_acl); -/* core_tpg_del_initiator_node_acl(): - * - * - */ -int core_tpg_del_initiator_node_acl( - struct se_portal_group *tpg, - struct se_node_acl *acl, - int force) +void core_tpg_del_initiator_node_acl(struct se_node_acl *acl) { + struct se_portal_group *tpg = acl->se_tpg; LIST_HEAD(sess_list); struct se_session *sess, *sess_tmp; unsigned long flags; @@ -505,9 +482,8 @@ int core_tpg_del_initiator_node_acl( tpg->se_tpg_tfo->tpg_get_tag(tpg), acl->queue_depth, tpg->se_tpg_tfo->get_fabric_name(), acl->initiatorname); - return 0; + tpg->se_tpg_tfo->tpg_release_fabric_acl(tpg, acl); } -EXPORT_SYMBOL(core_tpg_del_initiator_node_acl); /* core_tpg_set_initiator_node_queue_depth(): * diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c index 46b4387460e5..e179fdf76ddb 100644 --- a/drivers/target/tcm_fc/tfc_conf.c +++ b/drivers/target/tcm_fc/tfc_conf.c @@ -198,48 +198,17 @@ static struct configfs_attribute *ft_nacl_base_attrs[] = { * Add ACL for an initiator. The ACL is named arbitrarily. * The port_name and/or node_name are attributes. */ -static struct se_node_acl *ft_add_acl( - struct se_portal_group *se_tpg, - struct config_group *group, - const char *name) +static int ft_init_nodeacl(struct se_node_acl *nacl, const char *name) { - struct ft_node_acl *acl; - struct ft_tpg *tpg; + struct ft_node_acl *acl = + container_of(nacl, struct ft_node_acl, se_node_acl); u64 wwpn; - u32 q_depth; - - pr_debug("add acl %s\n", name); - tpg = container_of(se_tpg, struct ft_tpg, se_tpg); if (ft_parse_wwn(name, &wwpn, 1) < 0) - return ERR_PTR(-EINVAL); + return -EINVAL; - acl = kzalloc(sizeof(struct ft_node_acl), GFP_KERNEL); - if (!acl) - return ERR_PTR(-ENOMEM); acl->node_auth.port_name = wwpn; - - q_depth = 32; /* XXX bogus default - get from tpg? */ - return core_tpg_add_initiator_node_acl(&tpg->se_tpg, - &acl->se_node_acl, name, q_depth); -} - -static void ft_del_acl(struct se_node_acl *se_acl) -{ - struct se_portal_group *se_tpg = se_acl->se_tpg; - struct ft_tpg *tpg; - struct ft_node_acl *acl = container_of(se_acl, - struct ft_node_acl, se_node_acl); - - pr_debug("del acl %s\n", - config_item_name(&se_acl->acl_group.cg_item)); - - tpg = container_of(se_tpg, struct ft_tpg, se_tpg); - pr_debug("del acl %p se_acl %p tpg %p se_tpg %p\n", - acl, se_acl, tpg, &tpg->se_tpg); - - core_tpg_del_initiator_node_acl(&tpg->se_tpg, se_acl, 1); - kfree(acl); + return 0; } struct ft_node_acl *ft_acl_get(struct ft_tpg *tpg, struct fc_rport_priv *rdata) @@ -542,12 +511,7 @@ static const struct target_core_fabric_ops ft_fabric_ops = { .fabric_drop_wwn = &ft_del_wwn, .fabric_make_tpg = &ft_add_tpg, .fabric_drop_tpg = &ft_del_tpg, - .fabric_post_link = NULL, - .fabric_pre_unlink = NULL, - .fabric_make_np = NULL, - .fabric_drop_np = NULL, - .fabric_make_nodeacl = &ft_add_acl, - .fabric_drop_nodeacl = &ft_del_acl, + .fabric_init_nodeacl = &ft_init_nodeacl, .tfc_wwn_attrs = ft_wwn_attrs, .tfc_tpg_nacl_base_attrs = ft_nacl_base_attrs, diff --git a/drivers/usb/gadget/legacy/tcm_usb_gadget.c b/drivers/usb/gadget/legacy/tcm_usb_gadget.c index b7a78f72fb0e..fccb0ccb355a 100644 --- a/drivers/usb/gadget/legacy/tcm_usb_gadget.c +++ b/drivers/usb/gadget/legacy/tcm_usb_gadget.c @@ -1476,40 +1476,11 @@ static const char *usbg_check_wwn(const char *name) return n; } -static struct se_node_acl *usbg_make_nodeacl( - struct se_portal_group *se_tpg, - struct config_group *group, - const char *name) -{ - struct se_node_acl *se_nacl, *se_nacl_new; - u32 nexus_depth; - const char *wnn_name; - - wnn_name = usbg_check_wwn(name); - if (!wnn_name) - return ERR_PTR(-EINVAL); - se_nacl_new = usbg_alloc_fabric_acl(se_tpg); - if (!(se_nacl_new)) - return ERR_PTR(-ENOMEM); - - nexus_depth = 1; - /* - * se_nacl_new may be released by core_tpg_add_initiator_node_acl() - * when converting a NodeACL from demo mode -> explict - */ - se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new, - name, nexus_depth); - if (IS_ERR(se_nacl)) { - usbg_release_fabric_acl(se_tpg, se_nacl_new); - return se_nacl; - } - return se_nacl; -} - -static void usbg_drop_nodeacl(struct se_node_acl *se_acl) +static int usbg_init_nodeacl(struct se_node_acl *se_nacl, const char *name) { - core_tpg_del_initiator_node_acl(se_acl->se_tpg, se_acl, 1); - kfree(se_acl); + if (!usbg_check_wwn(name)) + return -EINVAL; + return 0; } struct usbg_tpg *the_only_tpg_I_currently_have; @@ -1879,10 +1850,7 @@ static const struct target_core_fabric_ops usbg_ops = { .fabric_drop_tpg = usbg_drop_tpg, .fabric_post_link = usbg_port_link, .fabric_pre_unlink = usbg_port_unlink, - .fabric_make_np = NULL, - .fabric_drop_np = NULL, - .fabric_make_nodeacl = usbg_make_nodeacl, - .fabric_drop_nodeacl = usbg_drop_nodeacl, + .fabric_init_nodeacl = usbg_init_nodeacl, .tfc_wwn_attrs = usbg_wwn_attrs, .tfc_tpg_base_attrs = usbg_base_attrs, diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index fb8a93d5bfba..8faa7f4abf23 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -1798,41 +1798,6 @@ static void vhost_scsi_port_unlink(struct se_portal_group *se_tpg, mutex_unlock(&vhost_scsi_mutex); } -static struct se_node_acl * -vhost_scsi_make_nodeacl(struct se_portal_group *se_tpg, - struct config_group *group, - const char *name) -{ - struct se_node_acl *se_nacl, *se_nacl_new; - u32 nexus_depth; - - /* vhost_scsi_parse_wwn(name, &wwpn, 1) < 0) - return ERR_PTR(-EINVAL); */ - se_nacl_new = vhost_scsi_alloc_fabric_acl(se_tpg); - if (!se_nacl_new) - return ERR_PTR(-ENOMEM); - - nexus_depth = 1; - /* - * se_nacl_new may be released by core_tpg_add_initiator_node_acl() - * when converting a NodeACL from demo mode -> explict - */ - se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new, - name, nexus_depth); - if (IS_ERR(se_nacl)) { - vhost_scsi_release_fabric_acl(se_tpg, se_nacl_new); - return se_nacl; - } - - return se_nacl; -} - -static void vhost_scsi_drop_nodeacl(struct se_node_acl *se_acl) -{ - core_tpg_del_initiator_node_acl(se_acl->se_tpg, se_acl, 1); - kfree(se_acl); -} - static void vhost_scsi_free_cmd_map_res(struct vhost_scsi_nexus *nexus, struct se_session *se_sess) { @@ -2330,10 +2295,6 @@ static struct target_core_fabric_ops vhost_scsi_ops = { .fabric_drop_tpg = vhost_scsi_drop_tpg, .fabric_post_link = vhost_scsi_port_link, .fabric_pre_unlink = vhost_scsi_port_unlink, - .fabric_make_np = NULL, - .fabric_drop_np = NULL, - .fabric_make_nodeacl = vhost_scsi_make_nodeacl, - .fabric_drop_nodeacl = vhost_scsi_drop_nodeacl, .tfc_wwn_attrs = vhost_scsi_wwn_attrs, .tfc_tpg_base_attrs = vhost_scsi_tpg_attrs, diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index c0d4aee0eeb5..8a130ab71733 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -1980,12 +1980,6 @@ static const struct target_core_fabric_ops scsiback_ops = { .fabric_drop_tpg = scsiback_drop_tpg, .fabric_post_link = scsiback_port_link, .fabric_pre_unlink = scsiback_port_unlink, - .fabric_make_np = NULL, - .fabric_drop_np = NULL, -#if 0 - .fabric_make_nodeacl = scsiback_make_nodeacl, - .fabric_drop_nodeacl = scsiback_drop_nodeacl, -#endif .tfc_wwn_attrs = scsiback_wwn_attrs, .tfc_tpg_base_attrs = scsiback_tpg_attrs, diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index 24c8d9d0d946..8b570c49f4d1 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -88,9 +88,8 @@ struct target_core_fabric_ops { struct se_tpg_np *(*fabric_make_np)(struct se_portal_group *, struct config_group *, const char *); void (*fabric_drop_np)(struct se_tpg_np *); - struct se_node_acl *(*fabric_make_nodeacl)(struct se_portal_group *, - struct config_group *, const char *); - void (*fabric_drop_nodeacl)(struct se_node_acl *); + int (*fabric_init_nodeacl)(struct se_node_acl *, const char *); + void (*fabric_cleanup_nodeacl)(struct se_node_acl *); struct configfs_attribute **tfc_discovery_attrs; struct configfs_attribute **tfc_wwn_attrs; @@ -174,10 +173,6 @@ struct se_node_acl *core_tpg_get_initiator_node_acl(struct se_portal_group *tpg, struct se_node_acl *core_tpg_check_initiator_node_acl(struct se_portal_group *, unsigned char *); void core_tpg_clear_object_luns(struct se_portal_group *); -struct se_node_acl *core_tpg_add_initiator_node_acl(struct se_portal_group *, - struct se_node_acl *, const char *, u32); -int core_tpg_del_initiator_node_acl(struct se_portal_group *, - struct se_node_acl *, int); int core_tpg_set_initiator_node_queue_depth(struct se_portal_group *, unsigned char *, u32, int); int core_tpg_set_initiator_node_tag(struct se_portal_group *, -- cgit v1.2.3-70-g09d2 From e413f4727037e826c55a639c713a221006b6d61d Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 13 Apr 2015 19:51:15 +0200 Subject: target: refactor node ACL allocation Split out two common helpers to share code for allocating and initializing node ACLs. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_tpg.c | 133 +++++++++++++++++---------------------- 1 file changed, 56 insertions(+), 77 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index 78dd53ada04a..0cd86ff9a792 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -254,24 +254,12 @@ static int core_create_device_list_for_node(struct se_node_acl *nacl) return 0; } -/* core_tpg_check_initiator_node_acl() - * - * - */ -struct se_node_acl *core_tpg_check_initiator_node_acl( - struct se_portal_group *tpg, - unsigned char *initiatorname) +static struct se_node_acl *target_alloc_node_acl(struct se_portal_group *tpg, + const unsigned char *initiatorname) { struct se_node_acl *acl; - acl = core_tpg_get_initiator_node_acl(tpg, initiatorname); - if (acl) - return acl; - - if (!tpg->se_tpg_tfo->tpg_check_demo_mode(tpg)) - return NULL; - - acl = tpg->se_tpg_tfo->tpg_alloc_fabric_acl(tpg); + acl = tpg->se_tpg_tfo->tpg_alloc_fabric_acl(tpg); if (!acl) return NULL; @@ -289,20 +277,60 @@ struct se_node_acl *core_tpg_check_initiator_node_acl( snprintf(acl->initiatorname, TRANSPORT_IQN_LEN, "%s", initiatorname); acl->se_tpg = tpg; acl->acl_index = scsi_get_new_index(SCSI_AUTH_INTR_INDEX); - acl->dynamic_node_acl = 1; tpg->se_tpg_tfo->set_default_node_attributes(acl); - if (core_create_device_list_for_node(acl) < 0) { - tpg->se_tpg_tfo->tpg_release_fabric_acl(tpg, acl); + if (core_create_device_list_for_node(acl) < 0) + goto out_free_acl; + if (core_set_queue_depth_for_node(tpg, acl) < 0) + goto out_free_device_list; + + return acl; + +out_free_device_list: + core_free_device_list_for_node(acl, tpg); +out_free_acl: + tpg->se_tpg_tfo->tpg_release_fabric_acl(tpg, acl); + return NULL; +} + +static void target_add_node_acl(struct se_node_acl *acl) +{ + struct se_portal_group *tpg = acl->se_tpg; + + spin_lock_irq(&tpg->acl_node_lock); + list_add_tail(&acl->acl_list, &tpg->acl_node_list); + tpg->num_node_acls++; + spin_unlock_irq(&tpg->acl_node_lock); + + pr_debug("%s_TPG[%hu] - Added %s ACL with TCQ Depth: %d for %s" + " Initiator Node: %s\n", + tpg->se_tpg_tfo->get_fabric_name(), + tpg->se_tpg_tfo->tpg_get_tag(tpg), + acl->dynamic_node_acl ? "DYNAMIC" : "", + acl->queue_depth, + tpg->se_tpg_tfo->get_fabric_name(), + acl->initiatorname); +} + +struct se_node_acl *core_tpg_check_initiator_node_acl( + struct se_portal_group *tpg, + unsigned char *initiatorname) +{ + struct se_node_acl *acl; + + acl = core_tpg_get_initiator_node_acl(tpg, initiatorname); + if (acl) + return acl; + + if (!tpg->se_tpg_tfo->tpg_check_demo_mode(tpg)) return NULL; - } - if (core_set_queue_depth_for_node(tpg, acl) < 0) { - core_free_device_list_for_node(acl, tpg); - tpg->se_tpg_tfo->tpg_release_fabric_acl(tpg, acl); + acl = target_alloc_node_acl(tpg, initiatorname); + if (!acl) return NULL; - } + acl->dynamic_node_acl = 1; + /* * Here we only create demo-mode MappedLUNs from the active * TPG LUNs if the fabric is not explicitly asking for @@ -312,16 +340,7 @@ struct se_node_acl *core_tpg_check_initiator_node_acl( (tpg->se_tpg_tfo->tpg_check_demo_mode_login_only(tpg) != 1)) core_tpg_add_node_to_devs(acl, tpg); - spin_lock_irq(&tpg->acl_node_lock); - list_add_tail(&acl->acl_list, &tpg->acl_node_list); - tpg->num_node_acls++; - spin_unlock_irq(&tpg->acl_node_lock); - - pr_debug("%s_TPG[%u] - Added DYNAMIC ACL with TCQ Depth: %d for %s" - " Initiator Node: %s\n", tpg->se_tpg_tfo->get_fabric_name(), - tpg->se_tpg_tfo->tpg_get_tag(tpg), acl->queue_depth, - tpg->se_tpg_tfo->get_fabric_name(), initiatorname); - + target_add_node_acl(acl); return acl; } EXPORT_SYMBOL(core_tpg_check_initiator_node_acl); @@ -368,7 +387,7 @@ struct se_node_acl *core_tpg_add_initiator_node_acl( " for %s\n", tpg->se_tpg_tfo->get_fabric_name(), tpg->se_tpg_tfo->tpg_get_tag(tpg), initiatorname); spin_unlock_irq(&tpg->acl_node_lock); - goto done; + return acl; } pr_err("ACL entry for %s Initiator" @@ -380,51 +399,11 @@ struct se_node_acl *core_tpg_add_initiator_node_acl( } spin_unlock_irq(&tpg->acl_node_lock); - acl = tpg->se_tpg_tfo->tpg_alloc_fabric_acl(tpg); - if (!acl) { - pr_err("struct se_node_acl pointer is NULL\n"); - return ERR_PTR(-EINVAL); - } - - INIT_LIST_HEAD(&acl->acl_list); - INIT_LIST_HEAD(&acl->acl_sess_list); - kref_init(&acl->acl_kref); - init_completion(&acl->acl_free_comp); - spin_lock_init(&acl->device_list_lock); - spin_lock_init(&acl->nacl_sess_lock); - atomic_set(&acl->acl_pr_ref_count, 0); - if (tpg->se_tpg_tfo->tpg_get_default_depth) - acl->queue_depth = tpg->se_tpg_tfo->tpg_get_default_depth(tpg); - else - acl->queue_depth = 1; - snprintf(acl->initiatorname, TRANSPORT_IQN_LEN, "%s", initiatorname); - acl->se_tpg = tpg; - acl->acl_index = scsi_get_new_index(SCSI_AUTH_INTR_INDEX); - - tpg->se_tpg_tfo->set_default_node_attributes(acl); - - if (core_create_device_list_for_node(acl) < 0) { - tpg->se_tpg_tfo->tpg_release_fabric_acl(tpg, acl); + acl = target_alloc_node_acl(tpg, initiatorname); + if (!acl) return ERR_PTR(-ENOMEM); - } - - if (core_set_queue_depth_for_node(tpg, acl) < 0) { - core_free_device_list_for_node(acl, tpg); - tpg->se_tpg_tfo->tpg_release_fabric_acl(tpg, acl); - return ERR_PTR(-EINVAL); - } - - spin_lock_irq(&tpg->acl_node_lock); - list_add_tail(&acl->acl_list, &tpg->acl_node_list); - tpg->num_node_acls++; - spin_unlock_irq(&tpg->acl_node_lock); - -done: - pr_debug("%s_TPG[%hu] - Added ACL with TCQ Depth: %d for %s" - " Initiator Node: %s\n", tpg->se_tpg_tfo->get_fabric_name(), - tpg->se_tpg_tfo->tpg_get_tag(tpg), acl->queue_depth, - tpg->se_tpg_tfo->get_fabric_name(), initiatorname); + target_add_node_acl(acl); return acl; } -- cgit v1.2.3-70-g09d2 From 144bc4c2a42a0f42a32c106d53f5bf2724fbf098 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 13 Apr 2015 19:51:16 +0200 Subject: target: move node ACL allocation to core code Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- Documentation/target/tcm_mod_builder.py | 27 -------------------------- drivers/infiniband/ulp/srpt/ib_srpt.c | 25 +----------------------- drivers/infiniband/ulp/srpt/ib_srpt.h | 4 ++-- drivers/scsi/qla2xxx/tcm_qla2xxx.c | 29 ++-------------------------- drivers/scsi/qla2xxx/tcm_qla2xxx.h | 4 ++-- drivers/target/iscsi/iscsi_target_configfs.c | 26 +------------------------ drivers/target/loopback/tcm_loop.c | 15 -------------- drivers/target/sbp/sbp_target.c | 14 -------------- drivers/target/target_core_configfs.c | 8 -------- drivers/target/target_core_tpg.c | 9 +++++---- drivers/target/target_core_transport.c | 2 +- drivers/target/tcm_fc/tcm_fc.h | 2 +- drivers/target/tcm_fc/tfc_conf.c | 26 +------------------------ drivers/usb/gadget/legacy/tcm_usb_gadget.c | 14 -------------- drivers/vhost/scsi.c | 15 -------------- drivers/xen/xen-scsiback.c | 15 -------------- include/target/iscsi/iscsi_target_core.h | 2 +- include/target/target_core_fabric.h | 5 +---- 18 files changed, 18 insertions(+), 224 deletions(-) (limited to 'drivers') diff --git a/Documentation/target/tcm_mod_builder.py b/Documentation/target/tcm_mod_builder.py index 3e54809b3aa1..07e7ef3d7429 100755 --- a/Documentation/target/tcm_mod_builder.py +++ b/Documentation/target/tcm_mod_builder.py @@ -313,8 +313,6 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += " .tpg_check_demo_mode_cache = " + fabric_mod_name + "_check_true,\n" buf += " .tpg_check_demo_mode_write_protect = " + fabric_mod_name + "_check_true,\n" buf += " .tpg_check_prod_mode_write_protect = " + fabric_mod_name + "_check_false,\n" - buf += " .tpg_alloc_fabric_acl = " + fabric_mod_name + "_alloc_fabric_acl,\n" - buf += " .tpg_release_fabric_acl = " + fabric_mod_name + "_release_fabric_acl,\n" buf += " .tpg_get_inst_index = " + fabric_mod_name + "_tpg_get_inst_index,\n" buf += " .release_cmd = " + fabric_mod_name + "_release_cmd,\n" buf += " .shutdown_session = " + fabric_mod_name + "_shutdown_session,\n" @@ -624,31 +622,6 @@ def tcm_mod_dump_fabric_ops(proto_ident, fabric_mod_dir_var, fabric_mod_name): bufi += "char *" + fabric_mod_name + "_parse_pr_out_transport_id(struct se_portal_group *,\n" bufi += " const char *, u32 *, char **);\n" - if re.search('alloc_fabric_acl\)\(', fo): - buf += "struct se_node_acl *" + fabric_mod_name + "_alloc_fabric_acl(struct se_portal_group *se_tpg)\n" - buf += "{\n" - buf += " struct " + fabric_mod_name + "_nacl *nacl;\n\n" - buf += " nacl = kzalloc(sizeof(struct " + fabric_mod_name + "_nacl), GFP_KERNEL);\n" - buf += " if (!nacl) {\n" - buf += " printk(KERN_ERR \"Unable to allocate struct " + fabric_mod_name + "_nacl\\n\");\n" - buf += " return NULL;\n" - buf += " }\n\n" - buf += " return &nacl->se_node_acl;\n" - buf += "}\n\n" - bufi += "struct se_node_acl *" + fabric_mod_name + "_alloc_fabric_acl(struct se_portal_group *);\n" - - if re.search('release_fabric_acl\)\(', fo): - buf += "void " + fabric_mod_name + "_release_fabric_acl(\n" - buf += " struct se_portal_group *se_tpg,\n" - buf += " struct se_node_acl *se_nacl)\n" - buf += "{\n" - buf += " struct " + fabric_mod_name + "_nacl *nacl = container_of(se_nacl,\n" - buf += " struct " + fabric_mod_name + "_nacl, se_node_acl);\n" - buf += " kfree(nacl);\n" - buf += "}\n\n" - bufi += "void " + fabric_mod_name + "_release_fabric_acl(struct se_portal_group *,\n" - bufi += " struct se_node_acl *);\n" - if re.search('tpg_get_inst_index\)\(', fo): buf += "u32 " + fabric_mod_name + "_tpg_get_inst_index(struct se_portal_group *se_tpg)\n" buf += "{\n" diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index c1f3aa52f42b..38e51f4a17de 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -3447,28 +3447,6 @@ static char *srpt_parse_pr_out_transport_id(struct se_portal_group *se_tpg, return (char *)tr_id->i_port_id; } -static struct se_node_acl *srpt_alloc_fabric_acl(struct se_portal_group *se_tpg) -{ - struct srpt_node_acl *nacl; - - nacl = kzalloc(sizeof(struct srpt_node_acl), GFP_KERNEL); - if (!nacl) { - pr_err("Unable to allocate struct srpt_node_acl\n"); - return NULL; - } - - return &nacl->nacl; -} - -static void srpt_release_fabric_acl(struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl) -{ - struct srpt_node_acl *nacl; - - nacl = container_of(se_nacl, struct srpt_node_acl, nacl); - kfree(nacl); -} - static u32 srpt_tpg_get_inst_index(struct se_portal_group *se_tpg) { return 1; @@ -3883,6 +3861,7 @@ static struct configfs_attribute *srpt_wwn_attrs[] = { static const struct target_core_fabric_ops srpt_template = { .module = THIS_MODULE, .name = "srpt", + .node_acl_size = sizeof(struct srpt_node_acl), .get_fabric_name = srpt_get_fabric_name, .get_fabric_proto_ident = srpt_get_fabric_proto_ident, .tpg_get_wwn = srpt_get_fabric_wwn, @@ -3894,8 +3873,6 @@ static const struct target_core_fabric_ops srpt_template = { .tpg_check_demo_mode_cache = srpt_check_true, .tpg_check_demo_mode_write_protect = srpt_check_true, .tpg_check_prod_mode_write_protect = srpt_check_false, - .tpg_alloc_fabric_acl = srpt_alloc_fabric_acl, - .tpg_release_fabric_acl = srpt_release_fabric_acl, .tpg_get_inst_index = srpt_tpg_get_inst_index, .release_cmd = srpt_release_cmd, .check_stop_free = srpt_check_stop_free, diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.h b/drivers/infiniband/ulp/srpt/ib_srpt.h index 3dae156905de..355f6f5ce8b2 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.h +++ b/drivers/infiniband/ulp/srpt/ib_srpt.h @@ -410,15 +410,15 @@ struct srpt_device { /** * struct srpt_node_acl - Per-initiator ACL data (managed via configfs). + * @nacl: Target core node ACL information. * @i_port_id: 128-bit SRP initiator port ID. * @sport: port information. - * @nacl: Target core node ACL information. * @list: Element of the per-HCA ACL list. */ struct srpt_node_acl { + struct se_node_acl nacl; u8 i_port_id[16]; struct srpt_port *sport; - struct se_node_acl nacl; struct list_head list; }; diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index a7ab689f5524..cb376e5198d0 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -338,29 +338,6 @@ static int tcm_qla2xxx_check_prot_fabric_only(struct se_portal_group *se_tpg) return tpg->tpg_attrib.fabric_prot_type; } -static struct se_node_acl *tcm_qla2xxx_alloc_fabric_acl( - struct se_portal_group *se_tpg) -{ - struct tcm_qla2xxx_nacl *nacl; - - nacl = kzalloc(sizeof(struct tcm_qla2xxx_nacl), GFP_KERNEL); - if (!nacl) { - pr_err("Unable to allocate struct tcm_qla2xxx_nacl\n"); - return NULL; - } - - return &nacl->se_node_acl; -} - -static void tcm_qla2xxx_release_fabric_acl( - struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl) -{ - struct tcm_qla2xxx_nacl *nacl = container_of(se_nacl, - struct tcm_qla2xxx_nacl, se_node_acl); - kfree(nacl); -} - static u32 tcm_qla2xxx_tpg_get_inst_index(struct se_portal_group *se_tpg) { struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, @@ -1949,6 +1926,7 @@ static struct configfs_attribute *tcm_qla2xxx_wwn_attrs[] = { static const struct target_core_fabric_ops tcm_qla2xxx_ops = { .module = THIS_MODULE, .name = "qla2xxx", + .node_acl_size = sizeof(struct tcm_qla2xxx_nacl), .get_fabric_name = tcm_qla2xxx_get_fabric_name, .get_fabric_proto_ident = tcm_qla2xxx_get_fabric_proto_ident, .tpg_get_wwn = tcm_qla2xxx_get_fabric_wwn, @@ -1964,8 +1942,6 @@ static const struct target_core_fabric_ops tcm_qla2xxx_ops = { tcm_qla2xxx_check_prod_write_protect, .tpg_check_prot_fabric_only = tcm_qla2xxx_check_prot_fabric_only, .tpg_check_demo_mode_login_only = tcm_qla2xxx_check_demo_mode_login_only, - .tpg_alloc_fabric_acl = tcm_qla2xxx_alloc_fabric_acl, - .tpg_release_fabric_acl = tcm_qla2xxx_release_fabric_acl, .tpg_get_inst_index = tcm_qla2xxx_tpg_get_inst_index, .check_stop_free = tcm_qla2xxx_check_stop_free, .release_cmd = tcm_qla2xxx_release_cmd, @@ -2001,6 +1977,7 @@ static const struct target_core_fabric_ops tcm_qla2xxx_ops = { static const struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = { .module = THIS_MODULE, .name = "qla2xxx_npiv", + .node_acl_size = sizeof(struct tcm_qla2xxx_nacl), .get_fabric_name = tcm_qla2xxx_npiv_get_fabric_name, .get_fabric_proto_ident = tcm_qla2xxx_get_fabric_proto_ident, .tpg_get_wwn = tcm_qla2xxx_get_fabric_wwn, @@ -2014,8 +1991,6 @@ static const struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = { .tpg_check_prod_mode_write_protect = tcm_qla2xxx_check_prod_write_protect, .tpg_check_demo_mode_login_only = tcm_qla2xxx_check_demo_mode_login_only, - .tpg_alloc_fabric_acl = tcm_qla2xxx_alloc_fabric_acl, - .tpg_release_fabric_acl = tcm_qla2xxx_release_fabric_acl, .tpg_get_inst_index = tcm_qla2xxx_tpg_get_inst_index, .check_stop_free = tcm_qla2xxx_check_stop_free, .release_cmd = tcm_qla2xxx_release_cmd, diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.h b/drivers/scsi/qla2xxx/tcm_qla2xxx.h index 23295115c9fc..3d805a07061c 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.h +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.h @@ -13,6 +13,8 @@ #include "qla_target.h" struct tcm_qla2xxx_nacl { + struct se_node_acl se_node_acl; + /* From libfc struct fc_rport->port_id */ u32 nport_id; /* Binary World Wide unique Node Name for remote FC Initiator Nport */ @@ -23,8 +25,6 @@ struct tcm_qla2xxx_nacl { struct qla_tgt_sess *qla_tgt_sess; /* Pointer to TCM FC nexus */ struct se_session *nport_nexus; - /* Returned by tcm_qla2xxx_make_nodeacl() */ - struct se_node_acl se_node_acl; }; struct tcm_qla2xxx_tpg_attrib { diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 7d9ff8cbbb5d..643024c1ee8d 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -860,20 +860,6 @@ static struct configfs_attribute *lio_target_initiator_attrs[] = { NULL, }; -static struct se_node_acl *lio_tpg_alloc_fabric_acl( - struct se_portal_group *se_tpg) -{ - struct iscsi_node_acl *acl; - - acl = kzalloc(sizeof(struct iscsi_node_acl), GFP_KERNEL); - if (!acl) { - pr_err("Unable to allocate memory for struct iscsi_node_acl\n"); - return NULL; - } - - return &acl->se_node_acl; -} - static int lio_target_init_nodeacl(struct se_node_acl *se_nacl, const char *name) { @@ -1868,15 +1854,6 @@ static int lio_tpg_check_prot_fabric_only( return tpg->tpg_attrib.fabric_prot_type; } -static void lio_tpg_release_fabric_acl( - struct se_portal_group *se_tpg, - struct se_node_acl *se_acl) -{ - struct iscsi_node_acl *acl = container_of(se_acl, - struct iscsi_node_acl, se_node_acl); - kfree(acl); -} - /* * Called with spin_lock_bh(struct se_portal_group->session_lock) held.. * @@ -1952,6 +1929,7 @@ static void lio_release_cmd(struct se_cmd *se_cmd) const struct target_core_fabric_ops iscsi_ops = { .module = THIS_MODULE, .name = "iscsi", + .node_acl_size = sizeof(struct iscsi_node_acl), .get_fabric_name = iscsi_get_fabric_name, .get_fabric_proto_ident = iscsi_get_fabric_proto_ident, .tpg_get_wwn = lio_tpg_get_endpoint_wwn, @@ -1967,8 +1945,6 @@ const struct target_core_fabric_ops iscsi_ops = { .tpg_check_prod_mode_write_protect = lio_tpg_check_prod_mode_write_protect, .tpg_check_prot_fabric_only = &lio_tpg_check_prot_fabric_only, - .tpg_alloc_fabric_acl = lio_tpg_alloc_fabric_acl, - .tpg_release_fabric_acl = lio_tpg_release_fabric_acl, .tpg_get_inst_index = lio_tpg_get_inst_index, .check_stop_free = lio_check_stop_free, .release_cmd = lio_release_cmd, diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 12b85b03e9ae..5a71c9f2ee66 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -698,19 +698,6 @@ static int tcm_loop_check_prot_fabric_only(struct se_portal_group *se_tpg) return tl_tpg->tl_fabric_prot_type; } -static struct se_node_acl *tcm_loop_tpg_alloc_fabric_acl( - struct se_portal_group *se_tpg) -{ - return kzalloc(sizeof(struct se_node_acl), GFP_KERNEL); -} - -static void tcm_loop_tpg_release_fabric_acl( - struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl) -{ - kfree(se_nacl); -} - static u32 tcm_loop_get_inst_index(struct se_portal_group *se_tpg) { return 1; @@ -1383,8 +1370,6 @@ static const struct target_core_fabric_ops loop_ops = { .tpg_check_prod_mode_write_protect = tcm_loop_check_prod_mode_write_protect, .tpg_check_prot_fabric_only = tcm_loop_check_prot_fabric_only, - .tpg_alloc_fabric_acl = tcm_loop_tpg_alloc_fabric_acl, - .tpg_release_fabric_acl = tcm_loop_tpg_release_fabric_acl, .tpg_get_inst_index = tcm_loop_get_inst_index, .check_stop_free = tcm_loop_check_stop_free, .release_cmd = tcm_loop_release_cmd, diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index 3a47fe46fbca..5df2a61714fb 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -1707,18 +1707,6 @@ static u16 sbp_get_tag(struct se_portal_group *se_tpg) return tpg->tport_tpgt; } -static struct se_node_acl *sbp_alloc_fabric_acl(struct se_portal_group *se_tpg) -{ - return kzalloc(sizeof(struct se_node_acl), GFP_KERNEL); -} - -static void sbp_release_fabric_acl( - struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl) -{ - kfree(se_nacl); -} - static u32 sbp_tpg_get_inst_index(struct se_portal_group *se_tpg) { return 1; @@ -2465,8 +2453,6 @@ static const struct target_core_fabric_ops sbp_ops = { .tpg_check_demo_mode_cache = sbp_check_true, .tpg_check_demo_mode_write_protect = sbp_check_false, .tpg_check_prod_mode_write_protect = sbp_check_false, - .tpg_alloc_fabric_acl = sbp_alloc_fabric_acl, - .tpg_release_fabric_acl = sbp_release_fabric_acl, .tpg_get_inst_index = sbp_tpg_get_inst_index, .release_cmd = sbp_release_cmd, .shutdown_session = sbp_shutdown_session, diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index c87ca0c50545..2b10499264d3 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -354,14 +354,6 @@ static int target_fabric_tf_ops_check(const struct target_core_fabric_ops *tfo) pr_err("Missing tfo->tpg_check_prod_mode_write_protect()\n"); return -EINVAL; } - if (!tfo->tpg_alloc_fabric_acl) { - pr_err("Missing tfo->tpg_alloc_fabric_acl()\n"); - return -EINVAL; - } - if (!tfo->tpg_release_fabric_acl) { - pr_err("Missing tfo->tpg_release_fabric_acl()\n"); - return -EINVAL; - } if (!tfo->tpg_get_inst_index) { pr_err("Missing tfo->tpg_get_inst_index()\n"); return -EINVAL; diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index 0cd86ff9a792..42f3bd9561c8 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -259,7 +259,8 @@ static struct se_node_acl *target_alloc_node_acl(struct se_portal_group *tpg, { struct se_node_acl *acl; - acl = tpg->se_tpg_tfo->tpg_alloc_fabric_acl(tpg); + acl = kzalloc(max(sizeof(*acl), tpg->se_tpg_tfo->node_acl_size), + GFP_KERNEL); if (!acl) return NULL; @@ -290,7 +291,7 @@ static struct se_node_acl *target_alloc_node_acl(struct se_portal_group *tpg, out_free_device_list: core_free_device_list_for_node(acl, tpg); out_free_acl: - tpg->se_tpg_tfo->tpg_release_fabric_acl(tpg, acl); + kfree(acl); return NULL; } @@ -461,7 +462,7 @@ void core_tpg_del_initiator_node_acl(struct se_node_acl *acl) tpg->se_tpg_tfo->tpg_get_tag(tpg), acl->queue_depth, tpg->se_tpg_tfo->get_fabric_name(), acl->initiatorname); - tpg->se_tpg_tfo->tpg_release_fabric_acl(tpg, acl); + kfree(acl); } /* core_tpg_set_initiator_node_queue_depth(): @@ -725,7 +726,7 @@ int core_tpg_deregister(struct se_portal_group *se_tpg) core_tpg_wait_for_nacl_pr_ref(nacl); core_free_device_list_for_node(nacl, se_tpg); - se_tpg->se_tpg_tfo->tpg_release_fabric_acl(se_tpg, nacl); + kfree(nacl); spin_lock_irq(&se_tpg->acl_node_lock); } diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 9dc1bd5f0e6b..0fc4f5cb4bea 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -533,7 +533,7 @@ void transport_deregister_session(struct se_session *se_sess) spin_unlock_irqrestore(&se_tpg->acl_node_lock, flags); core_tpg_wait_for_nacl_pr_ref(se_nacl); core_free_device_list_for_node(se_nacl, se_tpg); - se_tfo->tpg_release_fabric_acl(se_tpg, se_nacl); + kfree(se_nacl); comp_nacl = false; spin_lock_irqsave(&se_tpg->acl_node_lock, flags); diff --git a/drivers/target/tcm_fc/tcm_fc.h b/drivers/target/tcm_fc/tcm_fc.h index 881deb3d499a..4ceaeb9a4b93 100644 --- a/drivers/target/tcm_fc/tcm_fc.h +++ b/drivers/target/tcm_fc/tcm_fc.h @@ -80,8 +80,8 @@ struct ft_node_auth { * Node ACL for FC remote port session. */ struct ft_node_acl { - struct ft_node_auth node_auth; struct se_node_acl se_node_acl; + struct ft_node_auth node_auth; }; struct ft_lun { diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c index e179fdf76ddb..8da159352315 100644 --- a/drivers/target/tcm_fc/tfc_conf.c +++ b/drivers/target/tcm_fc/tfc_conf.c @@ -236,29 +236,6 @@ struct ft_node_acl *ft_acl_get(struct ft_tpg *tpg, struct fc_rport_priv *rdata) return found; } -static struct se_node_acl *ft_tpg_alloc_fabric_acl(struct se_portal_group *se_tpg) -{ - struct ft_node_acl *acl; - - acl = kzalloc(sizeof(*acl), GFP_KERNEL); - if (!acl) { - pr_err("Unable to allocate struct ft_node_acl\n"); - return NULL; - } - pr_debug("acl %p\n", acl); - return &acl->se_node_acl; -} - -static void ft_tpg_release_fabric_acl(struct se_portal_group *se_tpg, - struct se_node_acl *se_acl) -{ - struct ft_node_acl *acl = container_of(se_acl, - struct ft_node_acl, se_node_acl); - - pr_debug("acl %p\n", acl); - kfree(acl); -} - /* * local_port port_group (tpg) ops. */ @@ -474,6 +451,7 @@ static u32 ft_tpg_get_inst_index(struct se_portal_group *se_tpg) static const struct target_core_fabric_ops ft_fabric_ops = { .module = THIS_MODULE, .name = "fc", + .node_acl_size = sizeof(struct ft_node_acl), .get_fabric_name = ft_get_fabric_name, .get_fabric_proto_ident = fc_get_fabric_proto_ident, .tpg_get_wwn = ft_get_fabric_wwn, @@ -485,8 +463,6 @@ static const struct target_core_fabric_ops ft_fabric_ops = { .tpg_check_demo_mode_cache = ft_check_false, .tpg_check_demo_mode_write_protect = ft_check_false, .tpg_check_prod_mode_write_protect = ft_check_false, - .tpg_alloc_fabric_acl = ft_tpg_alloc_fabric_acl, - .tpg_release_fabric_acl = ft_tpg_release_fabric_acl, .tpg_get_inst_index = ft_tpg_get_inst_index, .check_stop_free = ft_check_stop_free, .release_cmd = ft_release_cmd, diff --git a/drivers/usb/gadget/legacy/tcm_usb_gadget.c b/drivers/usb/gadget/legacy/tcm_usb_gadget.c index fccb0ccb355a..82f4da8bfe41 100644 --- a/drivers/usb/gadget/legacy/tcm_usb_gadget.c +++ b/drivers/usb/gadget/legacy/tcm_usb_gadget.c @@ -1373,18 +1373,6 @@ static char *usbg_parse_pr_out_transport_id( return tid; } -static struct se_node_acl *usbg_alloc_fabric_acl(struct se_portal_group *se_tpg) -{ - return kzalloc(sizeof(struct se_node_acl), GFP_KERNEL); -} - -static void usbg_release_fabric_acl( - struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl) -{ - kfree(se_nacl); -} - static u32 usbg_tpg_get_inst_index(struct se_portal_group *se_tpg) { return 1; @@ -1825,8 +1813,6 @@ static const struct target_core_fabric_ops usbg_ops = { .tpg_check_demo_mode_cache = usbg_check_false, .tpg_check_demo_mode_write_protect = usbg_check_false, .tpg_check_prod_mode_write_protect = usbg_check_false, - .tpg_alloc_fabric_acl = usbg_alloc_fabric_acl, - .tpg_release_fabric_acl = usbg_release_fabric_acl, .tpg_get_inst_index = usbg_tpg_get_inst_index, .release_cmd = usbg_release_cmd, .shutdown_session = usbg_shutdown_session, diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index 8faa7f4abf23..b93c03935964 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -425,19 +425,6 @@ static int vhost_scsi_check_prot_fabric_only(struct se_portal_group *se_tpg) return tpg->tv_fabric_prot_type; } -static struct se_node_acl * -vhost_scsi_alloc_fabric_acl(struct se_portal_group *se_tpg) -{ - return kzalloc(sizeof(struct se_node_acl), GFP_KERNEL); -} - -static void -vhost_scsi_release_fabric_acl(struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl) -{ - kfree(se_nacl); -} - static u32 vhost_scsi_tpg_get_inst_index(struct se_portal_group *se_tpg) { return 1; @@ -2268,8 +2255,6 @@ static struct target_core_fabric_ops vhost_scsi_ops = { .tpg_check_demo_mode_write_protect = vhost_scsi_check_false, .tpg_check_prod_mode_write_protect = vhost_scsi_check_false, .tpg_check_prot_fabric_only = vhost_scsi_check_prot_fabric_only, - .tpg_alloc_fabric_acl = vhost_scsi_alloc_fabric_acl, - .tpg_release_fabric_acl = vhost_scsi_release_fabric_acl, .tpg_get_inst_index = vhost_scsi_tpg_get_inst_index, .release_cmd = vhost_scsi_release_cmd, .check_stop_free = vhost_scsi_check_stop_free, diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index 8a130ab71733..3756953b385b 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -1449,19 +1449,6 @@ static void scsiback_drop_tport(struct se_wwn *wwn) kfree(tport); } -static struct se_node_acl * -scsiback_alloc_fabric_acl(struct se_portal_group *se_tpg) -{ - return kzalloc(sizeof(struct se_node_acl), GFP_KERNEL); -} - -static void -scsiback_release_fabric_acl(struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl) -{ - kfree(se_nacl); -} - static u32 scsiback_tpg_get_inst_index(struct se_portal_group *se_tpg) { return 1; @@ -1952,8 +1939,6 @@ static const struct target_core_fabric_ops scsiback_ops = { .tpg_check_demo_mode_cache = scsiback_check_true, .tpg_check_demo_mode_write_protect = scsiback_check_false, .tpg_check_prod_mode_write_protect = scsiback_check_false, - .tpg_alloc_fabric_acl = scsiback_alloc_fabric_acl, - .tpg_release_fabric_acl = scsiback_release_fabric_acl, .tpg_get_inst_index = scsiback_tpg_get_inst_index, .check_stop_free = scsiback_check_stop_free, .release_cmd = scsiback_release_cmd, diff --git a/include/target/iscsi/iscsi_target_core.h b/include/target/iscsi/iscsi_target_core.h index 39f3d181d39d..f7b16ca67504 100644 --- a/include/target/iscsi/iscsi_target_core.h +++ b/include/target/iscsi/iscsi_target_core.h @@ -745,10 +745,10 @@ struct iscsi_node_stat_grps { }; struct iscsi_node_acl { + struct se_node_acl se_node_acl; struct iscsi_node_attrib node_attrib; struct iscsi_node_auth node_auth; struct iscsi_node_stat_grps node_stat_grps; - struct se_node_acl se_node_acl; }; struct iscsi_tpg_attrib { diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index 8b570c49f4d1..e5414744bf2d 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -4,6 +4,7 @@ struct target_core_fabric_ops { struct module *module; const char *name; + size_t node_acl_size; char *(*get_fabric_name)(void); u8 (*get_fabric_proto_ident)(struct se_portal_group *); char *(*tpg_get_wwn)(struct se_portal_group *); @@ -36,10 +37,6 @@ struct target_core_fabric_ops { * WRITE_STRIP and READ_INSERT operations. */ int (*tpg_check_prot_fabric_only)(struct se_portal_group *); - struct se_node_acl *(*tpg_alloc_fabric_acl)( - struct se_portal_group *); - void (*tpg_release_fabric_acl)(struct se_portal_group *, - struct se_node_acl *); u32 (*tpg_get_inst_index)(struct se_portal_group *); /* * Optional to release struct se_cmd and fabric dependent allocated -- cgit v1.2.3-70-g09d2 From 57636388af32c2c7db3919e8d53f4979b7c7c307 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Fri, 1 May 2015 15:23:48 +0900 Subject: target: Fix inconsistent address passed to kunmap_atomic() in sbc_dif_copy_prot() In sbc_dif_copy_prot(), the addresses passed to kunmap_atomic() are inconsistent with the addresses which are mapped by kmap_atomic(). That could be problematic if an SG element has its length larger than PAGE_SIZE as kunmap_atomic() will attempt to unmap different page. Signed-off-by: Akinobu Mita Cc: Nicholas Bellinger Cc: Sagi Grimberg Cc: "Martin K. Petersen" Cc: Christoph Hellwig Cc: "James E.J. Bottomley" Cc: target-devel@vger.kernel.org Cc: linux-scsi@vger.kernel.org Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_sbc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index d441975604db..d615a11dc9c9 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -1300,13 +1300,14 @@ void sbc_dif_copy_prot(struct se_cmd *cmd, unsigned int sectors, bool read, copied += len; psg_len -= len; + kunmap_atomic(addr - sg->offset - offset); + if (offset >= sg->length) { sg = sg_next(sg); offset = 0; } - kunmap_atomic(addr); } - kunmap_atomic(paddr); + kunmap_atomic(paddr - psg->offset); } } EXPORT_SYMBOL(sbc_dif_copy_prot); -- cgit v1.2.3-70-g09d2 From 5835812f13e56483f2c4907664bb43b0a78546b6 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Fri, 1 May 2015 15:23:49 +0900 Subject: target: ensure se_cmd->t_prot_sg is allocated when required Even if the device backend is initialized with protection info is enabled, some requests don't have the protection info attached for WRITE SAME command issued by block device helpers, WRITE command with WRPROTECT=0 by SG_IO ioctl, etc. So when TCM loopback fabric module is used, se_cmd->t_prot_sg is NULL for these requests and performing WRITE_INSERT of PI using software emulation by sbc_dif_generate() causes kernel crash. To fix this, introduce SCF_PASSTHROUGH_PROT_SG_TO_MEM_NOALLOC for se_cmd_flags, which is used to determine that se_cmd->t_prot_sg needs to be allocated or use pre-allocated protection information by scsi mid-layer. Signed-off-by: Akinobu Mita Cc: Nicholas Bellinger Cc: Sagi Grimberg Cc: "Martin K. Petersen" Cc: Christoph Hellwig Cc: "James E.J. Bottomley" Cc: target-devel@vger.kernel.org Cc: linux-scsi@vger.kernel.org Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 27 +++++++++++++++------------ include/target/target_core_base.h | 1 + 2 files changed, 16 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 0fc4f5cb4bea..85b021e749e6 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1448,6 +1448,7 @@ int target_submit_cmd_map_sgls(struct se_cmd *se_cmd, struct se_session *se_sess if (sgl_prot_count) { se_cmd->t_prot_sg = sgl_prot; se_cmd->t_prot_nents = sgl_prot_count; + se_cmd->se_cmd_flags |= SCF_PASSTHROUGH_PROT_SG_TO_MEM_NOALLOC; } /* @@ -2178,6 +2179,12 @@ static inline void transport_reset_sgl_orig(struct se_cmd *cmd) static inline void transport_free_pages(struct se_cmd *cmd) { + if (!(cmd->se_cmd_flags & SCF_PASSTHROUGH_PROT_SG_TO_MEM_NOALLOC)) { + transport_free_sgl(cmd->t_prot_sg, cmd->t_prot_nents); + cmd->t_prot_sg = NULL; + cmd->t_prot_nents = 0; + } + if (cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC) { /* * Release special case READ buffer payload required for @@ -2201,10 +2208,6 @@ static inline void transport_free_pages(struct se_cmd *cmd) transport_free_sgl(cmd->t_bidi_data_sg, cmd->t_bidi_data_nents); cmd->t_bidi_data_sg = NULL; cmd->t_bidi_data_nents = 0; - - transport_free_sgl(cmd->t_prot_sg, cmd->t_prot_nents); - cmd->t_prot_sg = NULL; - cmd->t_prot_nents = 0; } /** @@ -2343,6 +2346,14 @@ transport_generic_new_cmd(struct se_cmd *cmd) int ret = 0; bool zero_flag = !(cmd->se_cmd_flags & SCF_SCSI_DATA_CDB); + if (cmd->prot_op != TARGET_PROT_NORMAL && + !(cmd->se_cmd_flags & SCF_PASSTHROUGH_PROT_SG_TO_MEM_NOALLOC)) { + ret = target_alloc_sgl(&cmd->t_prot_sg, &cmd->t_prot_nents, + cmd->prot_length, true); + if (ret < 0) + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + } + /* * Determine is the TCM fabric module has already allocated physical * memory, and is directly calling transport_generic_map_mem_to_cmd() @@ -2368,14 +2379,6 @@ transport_generic_new_cmd(struct se_cmd *cmd) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } - if (cmd->prot_op != TARGET_PROT_NORMAL) { - ret = target_alloc_sgl(&cmd->t_prot_sg, - &cmd->t_prot_nents, - cmd->prot_length, true); - if (ret < 0) - return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - } - ret = target_alloc_sgl(&cmd->t_data_sg, &cmd->t_data_nents, cmd->data_length, zero_flag); if (ret < 0) diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 7f4c7de3a4ce..9f8f5a1b527d 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -161,6 +161,7 @@ enum se_cmd_flags_table { SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC = 0x00020000, SCF_COMPARE_AND_WRITE = 0x00080000, SCF_COMPARE_AND_WRITE_POST = 0x00100000, + SCF_PASSTHROUGH_PROT_SG_TO_MEM_NOALLOC = 0x00200000, }; /* struct se_dev_entry->lun_flags and struct se_lun->lun_access */ -- cgit v1.2.3-70-g09d2 From 18213afbd8cee9f8a3ac5294dedf543a06559c8b Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Fri, 1 May 2015 15:23:51 +0900 Subject: target: handle odd SG mapping for data transfer memory sbc_dif_generate() and sbc_dif_verify() currently assume that each SG element for data transfer memory doesn't straddle the block size boundary. However, when using SG_IO ioctl, we can choose the data transfer memory which doesn't satisfy that alignment requirement. In order to handle such cases correctly, this change inverts the outer loop to iterate data transfer memory and the inner loop to iterate protection information and enables to calculate CRC for a block which straddles multiple SG elements. Signed-off-by: Akinobu Mita Cc: Tim Chen Cc: Herbert Xu Cc: "David S. Miller" Cc: linux-crypto@vger.kernel.org Cc: Nicholas Bellinger Cc: Sagi Grimberg Cc: "Martin K. Petersen" Cc: Christoph Hellwig Cc: "James E.J. Bottomley" Cc: target-devel@vger.kernel.org Cc: linux-scsi@vger.kernel.org Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_sbc.c | 122 ++++++++++++++++++++++++++------------- 1 file changed, 83 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index d615a11dc9c9..31b2ae356120 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -1183,27 +1183,50 @@ sbc_dif_generate(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; struct se_dif_v1_tuple *sdt; - struct scatterlist *dsg, *psg = cmd->t_prot_sg; + struct scatterlist *dsg = cmd->t_data_sg, *psg; sector_t sector = cmd->t_task_lba; void *daddr, *paddr; int i, j, offset = 0; + unsigned int block_size = dev->dev_attrib.block_size; - for_each_sg(cmd->t_data_sg, dsg, cmd->t_data_nents, i) { - daddr = kmap_atomic(sg_page(dsg)) + dsg->offset; + for_each_sg(cmd->t_prot_sg, psg, cmd->t_prot_nents, i) { paddr = kmap_atomic(sg_page(psg)) + psg->offset; + daddr = kmap_atomic(sg_page(dsg)) + dsg->offset; - for (j = 0; j < dsg->length; j += dev->dev_attrib.block_size) { + for (j = 0; j < psg->length; + j += sizeof(struct se_dif_v1_tuple)) { + __u16 crc; + unsigned int avail; - if (offset >= psg->length) { - kunmap_atomic(paddr); - psg = sg_next(psg); - paddr = kmap_atomic(sg_page(psg)) + psg->offset; - offset = 0; + if (offset >= dsg->length) { + offset -= dsg->length; + kunmap_atomic(daddr - dsg->offset); + dsg = sg_next(dsg); + if (!dsg) { + kunmap_atomic(paddr - psg->offset); + return; + } + daddr = kmap_atomic(sg_page(dsg)) + dsg->offset; } - sdt = paddr + offset; - sdt->guard_tag = cpu_to_be16(crc_t10dif(daddr + j, - dev->dev_attrib.block_size)); + sdt = paddr + j; + avail = min(block_size, dsg->length - offset); + crc = crc_t10dif(daddr + offset, avail); + if (avail < block_size) { + kunmap_atomic(daddr - dsg->offset); + dsg = sg_next(dsg); + if (!dsg) { + kunmap_atomic(paddr - psg->offset); + return; + } + daddr = kmap_atomic(sg_page(dsg)) + dsg->offset; + offset = block_size - avail; + crc = crc_t10dif_update(crc, daddr, offset); + } else { + offset += block_size; + } + + sdt->guard_tag = cpu_to_be16(crc); if (cmd->prot_type == TARGET_DIF_TYPE1_PROT) sdt->ref_tag = cpu_to_be32(sector & 0xffffffff); sdt->app_tag = 0; @@ -1216,26 +1239,23 @@ sbc_dif_generate(struct se_cmd *cmd) be32_to_cpu(sdt->ref_tag)); sector++; - offset += sizeof(struct se_dif_v1_tuple); } - kunmap_atomic(paddr); - kunmap_atomic(daddr); + kunmap_atomic(daddr - dsg->offset); + kunmap_atomic(paddr - psg->offset); } } static sense_reason_t sbc_dif_v1_verify(struct se_cmd *cmd, struct se_dif_v1_tuple *sdt, - const void *p, sector_t sector, unsigned int ei_lba) + __u16 crc, sector_t sector, unsigned int ei_lba) { - struct se_device *dev = cmd->se_dev; - int block_size = dev->dev_attrib.block_size; __be16 csum; if (!(cmd->prot_checks & TARGET_DIF_CHECK_GUARD)) goto check_ref; - csum = cpu_to_be16(crc_t10dif(p, block_size)); + csum = cpu_to_be16(crc); if (sdt->guard_tag != csum) { pr_err("DIFv1 checksum failed on sector %llu guard tag 0x%04x" @@ -1318,26 +1338,36 @@ sbc_dif_verify(struct se_cmd *cmd, sector_t start, unsigned int sectors, { struct se_device *dev = cmd->se_dev; struct se_dif_v1_tuple *sdt; - struct scatterlist *dsg; + struct scatterlist *dsg = cmd->t_data_sg; sector_t sector = start; void *daddr, *paddr; - int i, j; + int i; sense_reason_t rc; + int dsg_off = 0; + unsigned int block_size = dev->dev_attrib.block_size; - for_each_sg(cmd->t_data_sg, dsg, cmd->t_data_nents, i) { - daddr = kmap_atomic(sg_page(dsg)) + dsg->offset; + for (; psg && sector < start + sectors; psg = sg_next(psg)) { paddr = kmap_atomic(sg_page(psg)) + psg->offset; + daddr = kmap_atomic(sg_page(dsg)) + dsg->offset; - for (j = 0; j < dsg->length; j += dev->dev_attrib.block_size) { + for (i = psg_off; i < psg->length && + sector < start + sectors; + i += sizeof(struct se_dif_v1_tuple)) { + __u16 crc; + unsigned int avail; - if (psg_off >= psg->length) { - kunmap_atomic(paddr - psg->offset); - psg = sg_next(psg); - paddr = kmap_atomic(sg_page(psg)) + psg->offset; - psg_off = 0; + if (dsg_off >= dsg->length) { + dsg_off -= dsg->length; + kunmap_atomic(daddr - dsg->offset); + dsg = sg_next(dsg); + if (!dsg) { + kunmap_atomic(paddr - psg->offset); + return 0; + } + daddr = kmap_atomic(sg_page(dsg)) + dsg->offset; } - sdt = paddr + psg_off; + sdt = paddr + i; pr_debug("DIF READ sector: %llu guard_tag: 0x%04x" " app_tag: 0x%04x ref_tag: %u\n", @@ -1345,27 +1375,41 @@ sbc_dif_verify(struct se_cmd *cmd, sector_t start, unsigned int sectors, sdt->app_tag, be32_to_cpu(sdt->ref_tag)); if (sdt->app_tag == cpu_to_be16(0xffff)) { - sector++; - psg_off += sizeof(struct se_dif_v1_tuple); - continue; + dsg_off += block_size; + goto next; + } + + avail = min(block_size, dsg->length - dsg_off); + crc = crc_t10dif(daddr + dsg_off, avail); + if (avail < block_size) { + kunmap_atomic(daddr - dsg->offset); + dsg = sg_next(dsg); + if (!dsg) { + kunmap_atomic(paddr - psg->offset); + return 0; + } + daddr = kmap_atomic(sg_page(dsg)) + dsg->offset; + dsg_off = block_size - avail; + crc = crc_t10dif_update(crc, daddr, dsg_off); + } else { + dsg_off += block_size; } - rc = sbc_dif_v1_verify(cmd, sdt, daddr + j, sector, - ei_lba); + rc = sbc_dif_v1_verify(cmd, sdt, crc, sector, ei_lba); if (rc) { - kunmap_atomic(paddr - psg->offset); kunmap_atomic(daddr - dsg->offset); + kunmap_atomic(paddr - psg->offset); cmd->bad_sector = sector; return rc; } - +next: sector++; ei_lba++; - psg_off += sizeof(struct se_dif_v1_tuple); } - kunmap_atomic(paddr - psg->offset); + psg_off = 0; kunmap_atomic(daddr - dsg->offset); + kunmap_atomic(paddr - psg->offset); } return 0; -- cgit v1.2.3-70-g09d2 From 2b6eb609b8fab75707ac3557d195a5a99037e39b Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 1 May 2015 17:47:53 +0200 Subject: target/iscsi: stop using se_tpg_fabric_ptr Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/iscsi/iscsi_target_configfs.c | 43 ++++++++++------------------ 1 file changed, 15 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 643024c1ee8d..03b2e15c1b6c 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -1789,69 +1789,58 @@ static void lio_aborted_task(struct se_cmd *se_cmd) cmd->conn->conn_transport->iscsit_aborted_task(cmd->conn, cmd); } -static char *lio_tpg_get_endpoint_wwn(struct se_portal_group *se_tpg) +static inline struct iscsi_portal_group *iscsi_tpg(struct se_portal_group *se_tpg) { - struct iscsi_portal_group *tpg = se_tpg->se_tpg_fabric_ptr; + return container_of(se_tpg, struct iscsi_portal_group, tpg_se_tpg); +} - return &tpg->tpg_tiqn->tiqn[0]; +static char *lio_tpg_get_endpoint_wwn(struct se_portal_group *se_tpg) +{ + return iscsi_tpg(se_tpg)->tpg_tiqn->tiqn; } static u16 lio_tpg_get_tag(struct se_portal_group *se_tpg) { - struct iscsi_portal_group *tpg = se_tpg->se_tpg_fabric_ptr; - - return tpg->tpgt; + return iscsi_tpg(se_tpg)->tpgt; } static u32 lio_tpg_get_default_depth(struct se_portal_group *se_tpg) { - struct iscsi_portal_group *tpg = se_tpg->se_tpg_fabric_ptr; - - return tpg->tpg_attrib.default_cmdsn_depth; + return iscsi_tpg(se_tpg)->tpg_attrib.default_cmdsn_depth; } static int lio_tpg_check_demo_mode(struct se_portal_group *se_tpg) { - struct iscsi_portal_group *tpg = se_tpg->se_tpg_fabric_ptr; - - return tpg->tpg_attrib.generate_node_acls; + return iscsi_tpg(se_tpg)->tpg_attrib.generate_node_acls; } static int lio_tpg_check_demo_mode_cache(struct se_portal_group *se_tpg) { - struct iscsi_portal_group *tpg = se_tpg->se_tpg_fabric_ptr; - - return tpg->tpg_attrib.cache_dynamic_acls; + return iscsi_tpg(se_tpg)->tpg_attrib.cache_dynamic_acls; } static int lio_tpg_check_demo_mode_write_protect( struct se_portal_group *se_tpg) { - struct iscsi_portal_group *tpg = se_tpg->se_tpg_fabric_ptr; - - return tpg->tpg_attrib.demo_mode_write_protect; + return iscsi_tpg(se_tpg)->tpg_attrib.demo_mode_write_protect; } static int lio_tpg_check_prod_mode_write_protect( struct se_portal_group *se_tpg) { - struct iscsi_portal_group *tpg = se_tpg->se_tpg_fabric_ptr; - - return tpg->tpg_attrib.prod_mode_write_protect; + return iscsi_tpg(se_tpg)->tpg_attrib.prod_mode_write_protect; } static int lio_tpg_check_prot_fabric_only( struct se_portal_group *se_tpg) { - struct iscsi_portal_group *tpg = se_tpg->se_tpg_fabric_ptr; /* * Only report fabric_prot_type if t10_pi has also been enabled * for incoming ib_isert sessions. */ - if (!tpg->tpg_attrib.t10_pi) + if (!iscsi_tpg(se_tpg)->tpg_attrib.t10_pi) return 0; - - return tpg->tpg_attrib.fabric_prot_type; + return iscsi_tpg(se_tpg)->tpg_attrib.fabric_prot_type; } /* @@ -1896,9 +1885,7 @@ static void lio_tpg_close_session(struct se_session *se_sess) static u32 lio_tpg_get_inst_index(struct se_portal_group *se_tpg) { - struct iscsi_portal_group *tpg = se_tpg->se_tpg_fabric_ptr; - - return tpg->tpg_tiqn->tiqn_index; + return iscsi_tpg(se_tpg)->tpg_tiqn->tiqn_index; } static void lio_set_default_node_attributes(struct se_node_acl *se_acl) -- cgit v1.2.3-70-g09d2 From 1667a459c382d4a90d05b0e8feab2d0b4ff27667 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 1 May 2015 17:47:54 +0200 Subject: tcm_loop: stop using se_tpg_fabric_ptr Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/loopback/tcm_loop.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 5a71c9f2ee66..9436bdfef091 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -520,10 +520,14 @@ static char *tcm_loop_get_fabric_name(void) return "loopback"; } +static inline struct tcm_loop_tpg *tl_tpg(struct se_portal_group *se_tpg) +{ + return container_of(se_tpg, struct tcm_loop_tpg, tl_se_tpg); +} + static u8 tcm_loop_get_fabric_proto_ident(struct se_portal_group *se_tpg) { - struct tcm_loop_tpg *tl_tpg = se_tpg->se_tpg_fabric_ptr; - struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba; + struct tcm_loop_hba *tl_hba = tl_tpg(se_tpg)->tl_hba; /* * tl_proto_id is set at tcm_loop_configfs.c:tcm_loop_make_scsi_hba() * time based on the protocol dependent prefix of the passed configfs group. @@ -549,21 +553,19 @@ static u8 tcm_loop_get_fabric_proto_ident(struct se_portal_group *se_tpg) static char *tcm_loop_get_endpoint_wwn(struct se_portal_group *se_tpg) { - struct tcm_loop_tpg *tl_tpg = se_tpg->se_tpg_fabric_ptr; /* * Return the passed NAA identifier for the SAS Target Port */ - return &tl_tpg->tl_hba->tl_wwn_address[0]; + return &tl_tpg(se_tpg)->tl_hba->tl_wwn_address[0]; } static u16 tcm_loop_get_tag(struct se_portal_group *se_tpg) { - struct tcm_loop_tpg *tl_tpg = se_tpg->se_tpg_fabric_ptr; /* * This Tag is used when forming SCSI Name identifier in EVPD=1 0x83 * to represent the SCSI Target Port. */ - return tl_tpg->tl_tpgt; + return tl_tpg(se_tpg)->tl_tpgt; } static u32 tcm_loop_get_pr_transport_id( @@ -573,8 +575,7 @@ static u32 tcm_loop_get_pr_transport_id( int *format_code, unsigned char *buf) { - struct tcm_loop_tpg *tl_tpg = se_tpg->se_tpg_fabric_ptr; - struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba; + struct tcm_loop_hba *tl_hba = tl_tpg(se_tpg)->tl_hba; switch (tl_hba->tl_proto_id) { case SCSI_PROTOCOL_SAS: @@ -602,8 +603,7 @@ static u32 tcm_loop_get_pr_transport_id_len( struct t10_pr_registration *pr_reg, int *format_code) { - struct tcm_loop_tpg *tl_tpg = se_tpg->se_tpg_fabric_ptr; - struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba; + struct tcm_loop_hba *tl_hba = tl_tpg(se_tpg)->tl_hba; switch (tl_hba->tl_proto_id) { case SCSI_PROTOCOL_SAS: @@ -635,8 +635,7 @@ static char *tcm_loop_parse_pr_out_transport_id( u32 *out_tid_len, char **port_nexus_ptr) { - struct tcm_loop_tpg *tl_tpg = se_tpg->se_tpg_fabric_ptr; - struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba; + struct tcm_loop_hba *tl_hba = tl_tpg(se_tpg)->tl_hba; switch (tl_hba->tl_proto_id) { case SCSI_PROTOCOL_SAS: -- cgit v1.2.3-70-g09d2 From 3868e4365f1735698df373733c9d99d7b9a688e8 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 1 May 2015 17:47:55 +0200 Subject: tcm_fc: stop using se_tpg_fabric_ptr Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/tcm_fc/tfc_conf.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c index 8da159352315..4bdf7a25ae67 100644 --- a/drivers/target/tcm_fc/tfc_conf.c +++ b/drivers/target/tcm_fc/tfc_conf.c @@ -409,6 +409,11 @@ static struct configfs_attribute *ft_wwn_attrs[] = { NULL, }; +static inline struct ft_tpg *ft_tpg(struct se_portal_group *se_tpg) +{ + return container_of(se_tpg, struct ft_tpg, se_tpg); +} + static char *ft_get_fabric_name(void) { return "fc"; @@ -416,20 +421,16 @@ static char *ft_get_fabric_name(void) static char *ft_get_fabric_wwn(struct se_portal_group *se_tpg) { - struct ft_tpg *tpg = se_tpg->se_tpg_fabric_ptr; - - return tpg->lport_wwn->name; + return ft_tpg(se_tpg)->lport_wwn->name; } static u16 ft_get_tag(struct se_portal_group *se_tpg) { - struct ft_tpg *tpg = se_tpg->se_tpg_fabric_ptr; - /* * This tag is used when forming SCSI Name identifier in EVPD=1 0x83 * to represent the SCSI Target Port. */ - return tpg->index; + return ft_tpg(se_tpg)->index; } static int ft_check_false(struct se_portal_group *se_tpg) @@ -443,9 +444,7 @@ static void ft_set_default_node_attr(struct se_node_acl *se_nacl) static u32 ft_tpg_get_inst_index(struct se_portal_group *se_tpg) { - struct ft_tpg *tpg = se_tpg->se_tpg_fabric_ptr; - - return tpg->index; + return ft_tpg(se_tpg)->index; } static const struct target_core_fabric_ops ft_fabric_ops = { -- cgit v1.2.3-70-g09d2 From e4aae5af810eaa61c2cd7ba79d95ebfe0d88fe9b Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 1 May 2015 17:47:56 +0200 Subject: target: change core_tpg_register prototype Remove the unneeded fabric_ptr argument, and change the type argument to pass in a SPC protocol identifier. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- Documentation/target/tcm_mod_builder.py | 3 +-- drivers/infiniband/ulp/srpt/ib_srpt.c | 2 +- drivers/scsi/qla2xxx/tcm_qla2xxx.c | 8 +++---- drivers/target/iscsi/iscsi_target_configfs.c | 2 +- drivers/target/iscsi/iscsi_target_tpg.c | 3 +-- drivers/target/loopback/tcm_loop.c | 4 ++-- drivers/target/sbp/sbp_target.c | 3 +-- drivers/target/target_core_tpg.c | 31 ++++++++++++---------------- drivers/target/tcm_fc/tfc_conf.c | 2 +- drivers/usb/gadget/legacy/tcm_usb_gadget.c | 4 ++-- drivers/vhost/scsi.c | 4 ++-- drivers/xen/xen-scsiback.c | 4 ++-- include/target/target_core_base.h | 16 ++++++-------- include/target/target_core_fabric.h | 2 +- 14 files changed, 38 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/Documentation/target/tcm_mod_builder.py b/Documentation/target/tcm_mod_builder.py index 07e7ef3d7429..b04846e985d4 100755 --- a/Documentation/target/tcm_mod_builder.py +++ b/Documentation/target/tcm_mod_builder.py @@ -238,8 +238,7 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += " tpg->" + fabric_mod_port + " = " + fabric_mod_port + ";\n" buf += " tpg->" + fabric_mod_port + "_tpgt = tpgt;\n\n" buf += " ret = core_tpg_register(&" + fabric_mod_name + "_ops, wwn,\n" - buf += " &tpg->se_tpg, tpg,\n" - buf += " TRANSPORT_TPG_TYPE_NORMAL);\n" + buf += " &tpg->se_tpg, SCSI_PROTOCOL_SAS);\n" buf += " if (ret < 0) {\n" buf += " kfree(tpg);\n" buf += " return NULL;\n" diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 38e51f4a17de..8eed6089c5d7 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -3791,7 +3791,7 @@ static struct se_portal_group *srpt_make_tpg(struct se_wwn *wwn, /* Initialize sport->port_wwn and sport->port_tpg_1 */ res = core_tpg_register(&srpt_template, &sport->port_wwn, - &sport->port_tpg_1, sport, TRANSPORT_TPG_TYPE_NORMAL); + &sport->port_tpg_1, SCSI_PROTOCOL_SRP); if (res) return ERR_PTR(res); diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index cb376e5198d0..30cbfa6dc3e6 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -1113,8 +1113,8 @@ static struct se_portal_group *tcm_qla2xxx_make_tpg( tpg->tpg_attrib.cache_dynamic_acls = 1; tpg->tpg_attrib.demo_mode_login_only = 1; - ret = core_tpg_register(&tcm_qla2xxx_ops, wwn, - &tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL); + ret = core_tpg_register(&tcm_qla2xxx_ops, wwn, &tpg->se_tpg, + SCSI_PROTOCOL_FCP); if (ret < 0) { kfree(tpg); return NULL; @@ -1233,8 +1233,8 @@ static struct se_portal_group *tcm_qla2xxx_npiv_make_tpg( tpg->tpg_attrib.cache_dynamic_acls = 1; tpg->tpg_attrib.demo_mode_login_only = 1; - ret = core_tpg_register(&tcm_qla2xxx_npiv_ops, wwn, - &tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL); + ret = core_tpg_register(&tcm_qla2xxx_npiv_ops, wwn, &tpg->se_tpg, + SCSI_PROTOCOL_FCP); if (ret < 0) { kfree(tpg); return NULL; diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 03b2e15c1b6c..0d5d88817a47 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -1421,7 +1421,7 @@ static struct se_portal_group *lio_target_tiqn_addtpg( return NULL; ret = core_tpg_register(&iscsi_ops, wwn, &tpg->tpg_se_tpg, - tpg, TRANSPORT_TPG_TYPE_NORMAL); + SCSI_PROTOCOL_ISCSI); if (ret < 0) return NULL; diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c index 5e3295fe404d..dcb7ede1d4aa 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.c +++ b/drivers/target/iscsi/iscsi_target_tpg.c @@ -68,8 +68,7 @@ int iscsit_load_discovery_tpg(void) return -1; } - ret = core_tpg_register(&iscsi_ops, NULL, &tpg->tpg_se_tpg, - tpg, TRANSPORT_TPG_TYPE_DISCOVERY); + ret = core_tpg_register(&iscsi_ops, NULL, &tpg->tpg_se_tpg, -1); if (ret < 0) { kfree(tpg); return -1; diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 9436bdfef091..3f264d436737 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -1204,8 +1204,8 @@ static struct se_portal_group *tcm_loop_make_naa_tpg( /* * Register the tl_tpg as a emulated SAS TCM Target Endpoint */ - ret = core_tpg_register(&loop_ops, wwn, &tl_tpg->tl_se_tpg, tl_tpg, - TRANSPORT_TPG_TYPE_NORMAL); + ret = core_tpg_register(&loop_ops, wwn, &tl_tpg->tl_se_tpg, + tl_hba->tl_proto_id); if (ret < 0) return ERR_PTR(-ENOMEM); diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index 5df2a61714fb..40b9f516cf9b 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -2152,8 +2152,7 @@ static struct se_portal_group *sbp_make_tpg( goto out_free_tpg; } - ret = core_tpg_register(&sbp_ops, wwn, &tpg->se_tpg, tpg, - TRANSPORT_TPG_TYPE_NORMAL); + ret = core_tpg_register(&sbp_ops, wwn, &tpg->se_tpg, SCSI_PROTOCOL_SBP); if (ret < 0) goto out_unreg_mgt_agt; diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index 42f3bd9561c8..c0c1f67facb5 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -634,8 +634,7 @@ int core_tpg_register( const struct target_core_fabric_ops *tfo, struct se_wwn *se_wwn, struct se_portal_group *se_tpg, - void *tpg_fabric_ptr, - int se_tpg_type) + int proto_id) { struct se_lun *lun; u32 i; @@ -661,8 +660,7 @@ int core_tpg_register( init_completion(&lun->lun_ref_comp); } - se_tpg->se_tpg_type = se_tpg_type; - se_tpg->se_tpg_fabric_ptr = tpg_fabric_ptr; + se_tpg->proto_id = proto_id; se_tpg->se_tpg_tfo = tfo; se_tpg->se_tpg_wwn = se_wwn; atomic_set(&se_tpg->tpg_pr_ref_count, 0); @@ -673,7 +671,7 @@ int core_tpg_register( spin_lock_init(&se_tpg->session_lock); spin_lock_init(&se_tpg->tpg_lun_lock); - if (se_tpg->se_tpg_type == TRANSPORT_TPG_TYPE_NORMAL) { + if (se_tpg->proto_id >= 0) { if (core_tpg_setup_virtual_lun0(se_tpg) < 0) { array_free(se_tpg->tpg_lun_list, TRANSPORT_MAX_LUNS_PER_TPG); @@ -685,11 +683,10 @@ int core_tpg_register( list_add_tail(&se_tpg->se_tpg_node, &tpg_list); spin_unlock_bh(&tpg_lock); - pr_debug("TARGET_CORE[%s]: Allocated %s struct se_portal_group for" - " endpoint: %s, Portal Tag: %u\n", tfo->get_fabric_name(), - (se_tpg->se_tpg_type == TRANSPORT_TPG_TYPE_NORMAL) ? - "Normal" : "Discovery", (tfo->tpg_get_wwn(se_tpg) == NULL) ? - "None" : tfo->tpg_get_wwn(se_tpg), tfo->tpg_get_tag(se_tpg)); + pr_debug("TARGET_CORE[%s]: Allocated portal_group for endpoint: %s, " + "Proto: %d, Portal Tag: %u\n", tfo->get_fabric_name(), + tfo->tpg_get_wwn(se_tpg) ? tfo->tpg_get_wwn(se_tpg) : NULL, + se_tpg->proto_id, tfo->tpg_get_tag(se_tpg)); return 0; } @@ -697,14 +694,13 @@ EXPORT_SYMBOL(core_tpg_register); int core_tpg_deregister(struct se_portal_group *se_tpg) { + const struct target_core_fabric_ops *tfo = se_tpg->se_tpg_tfo; struct se_node_acl *nacl, *nacl_tmp; - pr_debug("TARGET_CORE[%s]: Deallocating %s struct se_portal_group" - " for endpoint: %s Portal Tag %u\n", - (se_tpg->se_tpg_type == TRANSPORT_TPG_TYPE_NORMAL) ? - "Normal" : "Discovery", se_tpg->se_tpg_tfo->get_fabric_name(), - se_tpg->se_tpg_tfo->tpg_get_wwn(se_tpg), - se_tpg->se_tpg_tfo->tpg_get_tag(se_tpg)); + pr_debug("TARGET_CORE[%s]: Deallocating portal_group for endpoint: %s, " + "Proto: %d, Portal Tag: %u\n", tfo->get_fabric_name(), + tfo->tpg_get_wwn(se_tpg) ? tfo->tpg_get_wwn(se_tpg) : NULL, + se_tpg->proto_id, tfo->tpg_get_tag(se_tpg)); spin_lock_bh(&tpg_lock); list_del(&se_tpg->se_tpg_node); @@ -732,10 +728,9 @@ int core_tpg_deregister(struct se_portal_group *se_tpg) } spin_unlock_irq(&se_tpg->acl_node_lock); - if (se_tpg->se_tpg_type == TRANSPORT_TPG_TYPE_NORMAL) + if (se_tpg->proto_id >= 0) core_tpg_remove_lun(se_tpg, &se_tpg->tpg_virt_lun0); - se_tpg->se_tpg_fabric_ptr = NULL; array_free(se_tpg->tpg_lun_list, TRANSPORT_MAX_LUNS_PER_TPG); return 0; } diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c index 4bdf7a25ae67..8309c3d91387 100644 --- a/drivers/target/tcm_fc/tfc_conf.c +++ b/drivers/target/tcm_fc/tfc_conf.c @@ -284,7 +284,7 @@ static struct se_portal_group *ft_add_tpg( } ret = core_tpg_register(&ft_fabric_ops, wwn, &tpg->se_tpg, - tpg, TRANSPORT_TPG_TYPE_NORMAL); + SCSI_PROTOCOL_FCP); if (ret < 0) { destroy_workqueue(wq); kfree(tpg); diff --git a/drivers/usb/gadget/legacy/tcm_usb_gadget.c b/drivers/usb/gadget/legacy/tcm_usb_gadget.c index 82f4da8bfe41..08b4f48aa49e 100644 --- a/drivers/usb/gadget/legacy/tcm_usb_gadget.c +++ b/drivers/usb/gadget/legacy/tcm_usb_gadget.c @@ -1508,8 +1508,8 @@ static struct se_portal_group *usbg_make_tpg( tpg->tport = tport; tpg->tport_tpgt = tpgt; - ret = core_tpg_register(&usbg_ops, wwn, &tpg->se_tpg, tpg, - TRANSPORT_TPG_TYPE_NORMAL); + ret = core_tpg_register(&usbg_ops, wwn, &tpg->se_tpg, + tport->tport_proto_id); if (ret < 0) { destroy_workqueue(tpg->workqueue); kfree(tpg); diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index b93c03935964..8295e7be0fcb 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -2119,8 +2119,8 @@ vhost_scsi_make_tpg(struct se_wwn *wwn, tpg->tport = tport; tpg->tport_tpgt = tpgt; - ret = core_tpg_register(&vhost_scsi_ops, wwn, - &tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL); + ret = core_tpg_register(&vhost_scsi_ops, wwn, &tpg->se_tpg, + tport->tport_proto_id); if (ret < 0) { kfree(tpg); return NULL; diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index 3756953b385b..223d493878eb 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -1883,8 +1883,8 @@ scsiback_make_tpg(struct se_wwn *wwn, tpg->tport = tport; tpg->tport_tpgt = tpgt; - ret = core_tpg_register(&scsiback_ops, wwn, - &tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL); + ret = core_tpg_register(&scsiback_ops, wwn, &tpg->se_tpg, + tport->tport_proto_id); if (ret < 0) { kfree(tpg); return NULL; diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 9f8f5a1b527d..c462fb0a47f4 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -125,12 +125,6 @@ enum transport_lun_status_table { TRANSPORT_LUN_STATUS_ACTIVE = 1, }; -/* struct se_portal_group->se_tpg_type */ -enum transport_tpg_type_table { - TRANSPORT_TPG_TYPE_NORMAL = 0, - TRANSPORT_TPG_TYPE_DISCOVERY = 1, -}; - /* Special transport agnostic struct se_cmd->t_states */ enum transport_state_table { TRANSPORT_NO_STATE = 0, @@ -864,8 +858,12 @@ struct se_tpg_np { }; struct se_portal_group { - /* Type of target portal group, see transport_tpg_type_table */ - enum transport_tpg_type_table se_tpg_type; + /* + * PROTOCOL IDENTIFIER value per SPC4, 7.5.1. + * + * Negative values can be used by fabric drivers for internal use TPGs. + */ + int proto_id; /* Number of ACLed Initiator Nodes for this TPG */ u32 num_node_acls; /* Used for PR SPEC_I_PT=1 and REGISTER_AND_MOVE */ @@ -875,8 +873,6 @@ struct se_portal_group { /* Spinlock for adding/removing sessions */ spinlock_t session_lock; spinlock_t tpg_lun_lock; - /* Pointer to $FABRIC_MOD portal group */ - void *se_tpg_fabric_ptr; struct list_head se_tpg_node; /* linked list for initiator ACL list */ struct list_head acl_node_list; diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index e5414744bf2d..e0adc141de07 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -175,7 +175,7 @@ int core_tpg_set_initiator_node_queue_depth(struct se_portal_group *, int core_tpg_set_initiator_node_tag(struct se_portal_group *, struct se_node_acl *, const char *); int core_tpg_register(const struct target_core_fabric_ops *, - struct se_wwn *, struct se_portal_group *, void *, int); + struct se_wwn *, struct se_portal_group *, int); int core_tpg_deregister(struct se_portal_group *); /* SAS helpers */ -- cgit v1.2.3-70-g09d2 From 2aeeafae6bb9f04dbe17b521bcd8f0d03516c393 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 1 May 2015 17:47:57 +0200 Subject: target: remove the get_fabric_proto_ident method Now that we store the protocol identifier in the tpg structure we don't need this method. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- Documentation/target/tcm_mod_builder.py | 31 ---------------------------- drivers/infiniband/ulp/srpt/ib_srpt.c | 6 ------ drivers/scsi/qla2xxx/tcm_qla2xxx.c | 19 ----------------- drivers/target/iscsi/iscsi_target_configfs.c | 1 - drivers/target/loopback/tcm_loop.c | 27 ------------------------ drivers/target/sbp/sbp_target.c | 13 ------------ drivers/target/target_core_configfs.c | 4 ---- drivers/target/target_core_fabric_lib.c | 27 ------------------------ drivers/target/target_core_pr.c | 12 +++++------ drivers/target/target_core_spc.c | 12 ++++------- drivers/target/tcm_fc/tfc_conf.c | 1 - drivers/usb/gadget/legacy/tcm_usb_gadget.c | 18 ---------------- drivers/vhost/scsi.c | 23 --------------------- drivers/xen/xen-scsiback.c | 23 --------------------- include/target/target_core_fabric.h | 4 ---- 15 files changed, 9 insertions(+), 212 deletions(-) (limited to 'drivers') diff --git a/Documentation/target/tcm_mod_builder.py b/Documentation/target/tcm_mod_builder.py index b04846e985d4..29176c29537c 100755 --- a/Documentation/target/tcm_mod_builder.py +++ b/Documentation/target/tcm_mod_builder.py @@ -300,9 +300,7 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += "static const struct target_core_fabric_ops " + fabric_mod_name + "_ops = {\n" buf += " .module = THIS_MODULE,\n" buf += " .name = " + fabric_mod_name + ",\n" - buf += " .get_fabric_proto_ident = " + fabric_mod_name + "_get_fabric_proto_ident,\n" buf += " .get_fabric_name = " + fabric_mod_name + "_get_fabric_name,\n" - buf += " .get_fabric_proto_ident = " + fabric_mod_name + "_get_fabric_proto_ident,\n" buf += " .tpg_get_wwn = " + fabric_mod_name + "_get_fabric_wwn,\n" buf += " .tpg_get_tag = " + fabric_mod_name + "_get_tag,\n" buf += " .tpg_get_pr_transport_id = " + fabric_mod_name + "_get_pr_transport_id,\n" @@ -461,35 +459,6 @@ def tcm_mod_dump_fabric_ops(proto_ident, fabric_mod_dir_var, fabric_mod_name): bufi += "char *" + fabric_mod_name + "_get_fabric_name(void);\n" continue - if re.search('get_fabric_proto_ident', fo): - buf += "u8 " + fabric_mod_name + "_get_fabric_proto_ident(struct se_portal_group *se_tpg)\n" - buf += "{\n" - buf += " struct " + fabric_mod_name + "_tpg *tpg = container_of(se_tpg,\n" - buf += " struct " + fabric_mod_name + "_tpg, se_tpg);\n" - buf += " struct " + fabric_mod_name + "_" + fabric_mod_port + " *" + fabric_mod_port + " = tpg->" + fabric_mod_port + ";\n" - buf += " u8 proto_id;\n\n" - buf += " switch (" + fabric_mod_port + "->" + fabric_mod_port + "_proto_id) {\n" - if proto_ident == "FC": - buf += " case SCSI_PROTOCOL_FCP:\n" - buf += " default:\n" - buf += " proto_id = fc_get_fabric_proto_ident(se_tpg);\n" - buf += " break;\n" - elif proto_ident == "SAS": - buf += " case SCSI_PROTOCOL_SAS:\n" - buf += " default:\n" - buf += " proto_id = sas_get_fabric_proto_ident(se_tpg);\n" - buf += " break;\n" - elif proto_ident == "iSCSI": - buf += " case SCSI_PROTOCOL_ISCSI:\n" - buf += " default:\n" - buf += " proto_id = iscsi_get_fabric_proto_ident(se_tpg);\n" - buf += " break;\n" - - buf += " }\n\n" - buf += " return proto_id;\n" - buf += "}\n\n" - bufi += "u8 " + fabric_mod_name + "_get_fabric_proto_ident(struct se_portal_group *);\n" - if re.search('get_wwn', fo): buf += "char *" + fabric_mod_name + "_get_fabric_wwn(struct se_portal_group *se_tpg)\n" buf += "{\n" diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 8eed6089c5d7..9213c2de28fc 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -3394,11 +3394,6 @@ static char *srpt_get_fabric_name(void) return "srpt"; } -static u8 srpt_get_fabric_proto_ident(struct se_portal_group *se_tpg) -{ - return SCSI_TRANSPORTID_PROTOCOLID_SRP; -} - static char *srpt_get_fabric_wwn(struct se_portal_group *tpg) { struct srpt_port *sport = container_of(tpg, struct srpt_port, port_tpg_1); @@ -3863,7 +3858,6 @@ static const struct target_core_fabric_ops srpt_template = { .name = "srpt", .node_acl_size = sizeof(struct srpt_node_acl), .get_fabric_name = srpt_get_fabric_name, - .get_fabric_proto_ident = srpt_get_fabric_proto_ident, .tpg_get_wwn = srpt_get_fabric_wwn, .tpg_get_tag = srpt_get_tag, .tpg_get_pr_transport_id = srpt_get_pr_transport_id, diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 30cbfa6dc3e6..4566c4649751 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -190,23 +190,6 @@ static char *tcm_qla2xxx_npiv_get_fabric_name(void) return "qla2xxx_npiv"; } -static u8 tcm_qla2xxx_get_fabric_proto_ident(struct se_portal_group *se_tpg) -{ - struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, - struct tcm_qla2xxx_tpg, se_tpg); - struct tcm_qla2xxx_lport *lport = tpg->lport; - u8 proto_id; - - switch (lport->lport_proto_id) { - case SCSI_PROTOCOL_FCP: - default: - proto_id = fc_get_fabric_proto_ident(se_tpg); - break; - } - - return proto_id; -} - static char *tcm_qla2xxx_get_fabric_wwn(struct se_portal_group *se_tpg) { struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, @@ -1928,7 +1911,6 @@ static const struct target_core_fabric_ops tcm_qla2xxx_ops = { .name = "qla2xxx", .node_acl_size = sizeof(struct tcm_qla2xxx_nacl), .get_fabric_name = tcm_qla2xxx_get_fabric_name, - .get_fabric_proto_ident = tcm_qla2xxx_get_fabric_proto_ident, .tpg_get_wwn = tcm_qla2xxx_get_fabric_wwn, .tpg_get_tag = tcm_qla2xxx_get_tag, .tpg_get_pr_transport_id = tcm_qla2xxx_get_pr_transport_id, @@ -1979,7 +1961,6 @@ static const struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = { .name = "qla2xxx_npiv", .node_acl_size = sizeof(struct tcm_qla2xxx_nacl), .get_fabric_name = tcm_qla2xxx_npiv_get_fabric_name, - .get_fabric_proto_ident = tcm_qla2xxx_get_fabric_proto_ident, .tpg_get_wwn = tcm_qla2xxx_get_fabric_wwn, .tpg_get_tag = tcm_qla2xxx_get_tag, .tpg_get_pr_transport_id = tcm_qla2xxx_get_pr_transport_id, diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 0d5d88817a47..9dec9f39139f 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -1918,7 +1918,6 @@ const struct target_core_fabric_ops iscsi_ops = { .name = "iscsi", .node_acl_size = sizeof(struct iscsi_node_acl), .get_fabric_name = iscsi_get_fabric_name, - .get_fabric_proto_ident = iscsi_get_fabric_proto_ident, .tpg_get_wwn = lio_tpg_get_endpoint_wwn, .tpg_get_tag = lio_tpg_get_tag, .tpg_get_default_depth = lio_tpg_get_default_depth, diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 3f264d436737..0eed0209a7f4 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -525,32 +525,6 @@ static inline struct tcm_loop_tpg *tl_tpg(struct se_portal_group *se_tpg) return container_of(se_tpg, struct tcm_loop_tpg, tl_se_tpg); } -static u8 tcm_loop_get_fabric_proto_ident(struct se_portal_group *se_tpg) -{ - struct tcm_loop_hba *tl_hba = tl_tpg(se_tpg)->tl_hba; - /* - * tl_proto_id is set at tcm_loop_configfs.c:tcm_loop_make_scsi_hba() - * time based on the protocol dependent prefix of the passed configfs group. - * - * Based upon tl_proto_id, TCM_Loop emulates the requested fabric - * ProtocolID using target_core_fabric_lib.c symbols. - */ - switch (tl_hba->tl_proto_id) { - case SCSI_PROTOCOL_SAS: - return sas_get_fabric_proto_ident(se_tpg); - case SCSI_PROTOCOL_FCP: - return fc_get_fabric_proto_ident(se_tpg); - case SCSI_PROTOCOL_ISCSI: - return iscsi_get_fabric_proto_ident(se_tpg); - default: - pr_err("Unknown tl_proto_id: 0x%02x, using" - " SAS emulation\n", tl_hba->tl_proto_id); - break; - } - - return sas_get_fabric_proto_ident(se_tpg); -} - static char *tcm_loop_get_endpoint_wwn(struct se_portal_group *se_tpg) { /* @@ -1356,7 +1330,6 @@ static const struct target_core_fabric_ops loop_ops = { .module = THIS_MODULE, .name = "loopback", .get_fabric_name = tcm_loop_get_fabric_name, - .get_fabric_proto_ident = tcm_loop_get_fabric_proto_ident, .tpg_get_wwn = tcm_loop_get_endpoint_wwn, .tpg_get_tag = tcm_loop_get_tag, .tpg_get_pr_transport_id = tcm_loop_get_pr_transport_id, diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index 40b9f516cf9b..8acb37fd9ebc 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -1832,18 +1832,6 @@ static int sbp_check_stop_free(struct se_cmd *se_cmd) return 1; } -/* - * Handlers for Serial Bus Protocol 2/3 (SBP-2 / SBP-3) - */ -static u8 sbp_get_fabric_proto_ident(struct se_portal_group *se_tpg) -{ - /* - * Return a IEEE 1394 SCSI Protocol identifier for loopback operations - * This is defined in section 7.5.1 Table 362 in spc4r17 - */ - return SCSI_PROTOCOL_SBP; -} - static u32 sbp_get_pr_transport_id( struct se_portal_group *se_tpg, struct se_node_acl *se_nacl, @@ -2442,7 +2430,6 @@ static const struct target_core_fabric_ops sbp_ops = { .module = THIS_MODULE, .name = "sbp", .get_fabric_name = sbp_get_fabric_name, - .get_fabric_proto_ident = sbp_get_fabric_proto_ident, .tpg_get_wwn = sbp_get_fabric_wwn, .tpg_get_tag = sbp_get_tag, .tpg_get_pr_transport_id = sbp_get_pr_transport_id, diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 2b10499264d3..21c9f7d79d5e 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -318,10 +318,6 @@ static int target_fabric_tf_ops_check(const struct target_core_fabric_ops *tfo) pr_err("Missing tfo->get_fabric_name()\n"); return -EINVAL; } - if (!tfo->get_fabric_proto_ident) { - pr_err("Missing tfo->get_fabric_proto_ident()\n"); - return -EINVAL; - } if (!tfo->tpg_get_wwn) { pr_err("Missing tfo->tpg_get_wwn()\n"); return -EINVAL; diff --git a/drivers/target/target_core_fabric_lib.c b/drivers/target/target_core_fabric_lib.c index 35bfe77160d8..6fed14adbe61 100644 --- a/drivers/target/target_core_fabric_lib.c +++ b/drivers/target/target_core_fabric_lib.c @@ -42,16 +42,6 @@ /* * Handlers for Serial Attached SCSI (SAS) */ -u8 sas_get_fabric_proto_ident(struct se_portal_group *se_tpg) -{ - /* - * Return a SAS Serial SCSI Protocol identifier for loopback operations - * This is defined in section 7.5.1 Table 362 in spc4r17 - */ - return 0x6; -} -EXPORT_SYMBOL(sas_get_fabric_proto_ident); - u32 sas_get_pr_transport_id( struct se_portal_group *se_tpg, struct se_node_acl *se_nacl, @@ -128,12 +118,6 @@ EXPORT_SYMBOL(sas_parse_pr_out_transport_id); /* * Handlers for Fibre Channel Protocol (FCP) */ -u8 fc_get_fabric_proto_ident(struct se_portal_group *se_tpg) -{ - return 0x0; /* 0 = fcp-2 per SPC4 section 7.5.1 */ -} -EXPORT_SYMBOL(fc_get_fabric_proto_ident); - u32 fc_get_pr_transport_id_len( struct se_portal_group *se_tpg, struct se_node_acl *se_nacl, @@ -208,17 +192,6 @@ EXPORT_SYMBOL(fc_parse_pr_out_transport_id); /* * Handlers for Internet Small Computer Systems Interface (iSCSI) */ - -u8 iscsi_get_fabric_proto_ident(struct se_portal_group *se_tpg) -{ - /* - * This value is defined for "Internet SCSI (iSCSI)" - * in spc4r17 section 7.5.1 Table 362 - */ - return 0x5; -} -EXPORT_SYMBOL(iscsi_get_fabric_proto_ident); - u32 iscsi_get_pr_transport_id( struct se_portal_group *se_tpg, struct se_node_acl *se_nacl, diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index a15411c79ae9..23c065f83a56 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -1447,7 +1447,7 @@ core_scsi3_decode_spec_i_port( struct pr_transport_id_holder *tidh_new, *tidh, *tidh_tmp; const struct target_core_fabric_ops *tmp_tf_ops; unsigned char *buf; - unsigned char *ptr, *i_str = NULL, proto_ident, tmp_proto_ident; + unsigned char *ptr, *i_str = NULL, proto_ident; char *iport_ptr = NULL, i_buf[PR_REG_ISID_ID_LEN]; sense_reason_t ret; u32 tpdl, tid_len = 0; @@ -1536,15 +1536,13 @@ core_scsi3_decode_spec_i_port( tmp_tf_ops = tmp_tpg->se_tpg_tfo; if (!tmp_tf_ops) continue; - if (!tmp_tf_ops->get_fabric_proto_ident || - !tmp_tf_ops->tpg_parse_pr_out_transport_id) + if (!tmp_tf_ops->tpg_parse_pr_out_transport_id) continue; /* * Look for the matching proto_ident provided by * the received TransportID */ - tmp_proto_ident = tmp_tf_ops->get_fabric_proto_ident(tmp_tpg); - if (tmp_proto_ident != proto_ident) + if (tmp_tpg->proto_id != proto_ident) continue; dest_rtpi = tmp_port->sep_rtpi; @@ -3230,11 +3228,11 @@ core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key, pr_debug("SPC-3 PR REGISTER_AND_MOVE: Extracted Protocol Identifier:" " 0x%02x\n", proto_ident); - if (proto_ident != dest_tf_ops->get_fabric_proto_ident(dest_se_tpg)) { + if (proto_ident != dest_se_tpg->proto_id) { pr_err("SPC-3 PR REGISTER_AND_MOVE: Received" " proto_ident: 0x%02x does not match ident: 0x%02x" " from fabric: %s\n", proto_ident, - dest_tf_ops->get_fabric_proto_ident(dest_se_tpg), + dest_se_tpg->proto_id, dest_tf_ops->get_fabric_name()); ret = TCM_INVALID_PARAMETER_LIST; goto out; diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index 988c158cf65d..78c0b40fa5c0 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -286,8 +286,7 @@ check_t10_vend_desc: * Get the PROTOCOL IDENTIFIER as defined by spc4r17 * section 7.5.1 Table 362 */ - buf[off] = - (tpg->se_tpg_tfo->get_fabric_proto_ident(tpg) << 4); + buf[off] = tpg->proto_id << 4; buf[off++] |= 0x1; /* CODE SET == Binary */ buf[off] = 0x80; /* Set PIV=1 */ /* Set ASSOCIATION == target port: 01b */ @@ -322,8 +321,7 @@ check_t10_vend_desc: tg_pt_gp_id = tg_pt_gp->tg_pt_gp_id; spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - buf[off] = - (tpg->se_tpg_tfo->get_fabric_proto_ident(tpg) << 4); + buf[off] = tpg->proto_id << 4; buf[off++] |= 0x1; /* CODE SET == Binary */ buf[off] = 0x80; /* Set PIV=1 */ /* Set ASSOCIATION == target port: 01b */ @@ -371,8 +369,7 @@ check_lu_gp: * section 7.5.1 Table 362 */ check_scsi_name: - buf[off] = - (tpg->se_tpg_tfo->get_fabric_proto_ident(tpg) << 4); + buf[off] = tpg->proto_id << 4; buf[off++] |= 0x3; /* CODE SET == UTF-8 */ buf[off] = 0x80; /* Set PIV=1 */ /* Set ASSOCIATION == target port: 01b */ @@ -412,8 +409,7 @@ check_scsi_name: /* * Target device designator */ - buf[off] = - (tpg->se_tpg_tfo->get_fabric_proto_ident(tpg) << 4); + buf[off] = tpg->proto_id << 4; buf[off++] |= 0x3; /* CODE SET == UTF-8 */ buf[off] = 0x80; /* Set PIV=1 */ /* Set ASSOCIATION == target device: 10b */ diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c index 8309c3d91387..fabc7bacf693 100644 --- a/drivers/target/tcm_fc/tfc_conf.c +++ b/drivers/target/tcm_fc/tfc_conf.c @@ -452,7 +452,6 @@ static const struct target_core_fabric_ops ft_fabric_ops = { .name = "fc", .node_acl_size = sizeof(struct ft_node_acl), .get_fabric_name = ft_get_fabric_name, - .get_fabric_proto_ident = fc_get_fabric_proto_ident, .tpg_get_wwn = ft_get_fabric_wwn, .tpg_get_tag = ft_get_tag, .tpg_get_pr_transport_id = fc_get_pr_transport_id, diff --git a/drivers/usb/gadget/legacy/tcm_usb_gadget.c b/drivers/usb/gadget/legacy/tcm_usb_gadget.c index 08b4f48aa49e..d6b03178262f 100644 --- a/drivers/usb/gadget/legacy/tcm_usb_gadget.c +++ b/drivers/usb/gadget/legacy/tcm_usb_gadget.c @@ -1274,23 +1274,6 @@ static char *usbg_get_fabric_name(void) return "usb_gadget"; } -static u8 usbg_get_fabric_proto_ident(struct se_portal_group *se_tpg) -{ - struct usbg_tpg *tpg = container_of(se_tpg, - struct usbg_tpg, se_tpg); - struct usbg_tport *tport = tpg->tport; - u8 proto_id; - - switch (tport->tport_proto_id) { - case SCSI_PROTOCOL_SAS: - default: - proto_id = sas_get_fabric_proto_ident(se_tpg); - break; - } - - return proto_id; -} - static char *usbg_get_fabric_wwn(struct se_portal_group *se_tpg) { struct usbg_tpg *tpg = container_of(se_tpg, @@ -1803,7 +1786,6 @@ static const struct target_core_fabric_ops usbg_ops = { .module = THIS_MODULE, .name = "usb_gadget", .get_fabric_name = usbg_get_fabric_name, - .get_fabric_proto_ident = usbg_get_fabric_proto_ident, .tpg_get_wwn = usbg_get_fabric_wwn, .tpg_get_tag = usbg_get_tag, .tpg_get_pr_transport_id = usbg_get_pr_transport_id, diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index 8295e7be0fcb..022860ccd008 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -288,28 +288,6 @@ static char *vhost_scsi_get_fabric_name(void) return "vhost"; } -static u8 vhost_scsi_get_fabric_proto_ident(struct se_portal_group *se_tpg) -{ - struct vhost_scsi_tpg *tpg = container_of(se_tpg, - struct vhost_scsi_tpg, se_tpg); - struct vhost_scsi_tport *tport = tpg->tport; - - switch (tport->tport_proto_id) { - case SCSI_PROTOCOL_SAS: - return sas_get_fabric_proto_ident(se_tpg); - case SCSI_PROTOCOL_FCP: - return fc_get_fabric_proto_ident(se_tpg); - case SCSI_PROTOCOL_ISCSI: - return iscsi_get_fabric_proto_ident(se_tpg); - default: - pr_err("Unknown tport_proto_id: 0x%02x, using" - " SAS emulation\n", tport->tport_proto_id); - break; - } - - return sas_get_fabric_proto_ident(se_tpg); -} - static char *vhost_scsi_get_fabric_wwn(struct se_portal_group *se_tpg) { struct vhost_scsi_tpg *tpg = container_of(se_tpg, @@ -2244,7 +2222,6 @@ static struct target_core_fabric_ops vhost_scsi_ops = { .module = THIS_MODULE, .name = "vhost", .get_fabric_name = vhost_scsi_get_fabric_name, - .get_fabric_proto_ident = vhost_scsi_get_fabric_proto_ident, .tpg_get_wwn = vhost_scsi_get_fabric_wwn, .tpg_get_tag = vhost_scsi_get_tpgt, .tpg_get_pr_transport_id = vhost_scsi_get_pr_transport_id, diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index 223d493878eb..8bf9448bd7fd 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -1254,28 +1254,6 @@ static char *scsiback_dump_proto_id(struct scsiback_tport *tport) return "Unknown"; } -static u8 scsiback_get_fabric_proto_ident(struct se_portal_group *se_tpg) -{ - struct scsiback_tpg *tpg = container_of(se_tpg, - struct scsiback_tpg, se_tpg); - struct scsiback_tport *tport = tpg->tport; - - switch (tport->tport_proto_id) { - case SCSI_PROTOCOL_SAS: - return sas_get_fabric_proto_ident(se_tpg); - case SCSI_PROTOCOL_FCP: - return fc_get_fabric_proto_ident(se_tpg); - case SCSI_PROTOCOL_ISCSI: - return iscsi_get_fabric_proto_ident(se_tpg); - default: - pr_err("Unknown tport_proto_id: 0x%02x, using SAS emulation\n", - tport->tport_proto_id); - break; - } - - return sas_get_fabric_proto_ident(se_tpg); -} - static char *scsiback_get_fabric_wwn(struct se_portal_group *se_tpg) { struct scsiback_tpg *tpg = container_of(se_tpg, @@ -1929,7 +1907,6 @@ static const struct target_core_fabric_ops scsiback_ops = { .module = THIS_MODULE, .name = "xen-pvscsi", .get_fabric_name = scsiback_get_fabric_name, - .get_fabric_proto_ident = scsiback_get_fabric_proto_ident, .tpg_get_wwn = scsiback_get_fabric_wwn, .tpg_get_tag = scsiback_get_tag, .tpg_get_pr_transport_id = scsiback_get_pr_transport_id, diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index e0adc141de07..495606382546 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -6,7 +6,6 @@ struct target_core_fabric_ops { const char *name; size_t node_acl_size; char *(*get_fabric_name)(void); - u8 (*get_fabric_proto_ident)(struct se_portal_group *); char *(*tpg_get_wwn)(struct se_portal_group *); u16 (*tpg_get_tag)(struct se_portal_group *); u32 (*tpg_get_default_depth)(struct se_portal_group *); @@ -179,7 +178,6 @@ int core_tpg_register(const struct target_core_fabric_ops *, int core_tpg_deregister(struct se_portal_group *); /* SAS helpers */ -u8 sas_get_fabric_proto_ident(struct se_portal_group *); u32 sas_get_pr_transport_id(struct se_portal_group *, struct se_node_acl *, struct t10_pr_registration *, int *, unsigned char *); u32 sas_get_pr_transport_id_len(struct se_portal_group *, struct se_node_acl *, @@ -188,7 +186,6 @@ char *sas_parse_pr_out_transport_id(struct se_portal_group *, const char *, u32 *, char **); /* FC helpers */ -u8 fc_get_fabric_proto_ident(struct se_portal_group *); u32 fc_get_pr_transport_id(struct se_portal_group *, struct se_node_acl *, struct t10_pr_registration *, int *, unsigned char *); u32 fc_get_pr_transport_id_len(struct se_portal_group *, struct se_node_acl *, @@ -197,7 +194,6 @@ char *fc_parse_pr_out_transport_id(struct se_portal_group *, const char *, u32 *, char **); /* iSCSI helpers */ -u8 iscsi_get_fabric_proto_ident(struct se_portal_group *); u32 iscsi_get_pr_transport_id(struct se_portal_group *, struct se_node_acl *, struct t10_pr_registration *, int *, unsigned char *); u32 iscsi_get_pr_transport_id_len(struct se_portal_group *, struct se_node_acl *, -- cgit v1.2.3-70-g09d2 From 2650d71e244fb3637b5f58a0080682a8bf9c7091 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 1 May 2015 17:47:58 +0200 Subject: target: move transport ID handling to the core Now that struct se_portal_group contains a protocol identifier field we can take all the code to format an parse protocol identifiers in CDBs into common code instead of leaving this to low-level drivers. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- Documentation/target/tcm_mod_builder.py | 121 ------------ drivers/infiniband/ulp/srpt/ib_srpt.c | 39 ---- drivers/infiniband/ulp/srpt/ib_srpt.h | 18 -- drivers/scsi/qla2xxx/tcm_qla2xxx.c | 73 -------- drivers/scsi/qla2xxx/tcm_qla2xxx.h | 2 - drivers/target/iscsi/iscsi_target_configfs.c | 3 - drivers/target/loopback/tcm_loop.c | 92 ---------- drivers/target/sbp/sbp_target.c | 70 ------- drivers/target/target_core_configfs.c | 8 - drivers/target/target_core_fabric_lib.c | 263 ++++++++++++++------------- drivers/target/target_core_internal.h | 9 + drivers/target/target_core_pr.c | 49 +++-- drivers/target/tcm_fc/tfc_conf.c | 3 - drivers/usb/gadget/legacy/tcm_usb_gadget.c | 75 +------- drivers/usb/gadget/legacy/tcm_usb_gadget.h | 2 - drivers/vhost/scsi.c | 94 ---------- drivers/xen/xen-scsiback.c | 94 ---------- include/target/target_core_fabric.h | 33 ---- 18 files changed, 173 insertions(+), 875 deletions(-) (limited to 'drivers') diff --git a/Documentation/target/tcm_mod_builder.py b/Documentation/target/tcm_mod_builder.py index 29176c29537c..0dbd70cccde1 100755 --- a/Documentation/target/tcm_mod_builder.py +++ b/Documentation/target/tcm_mod_builder.py @@ -60,8 +60,6 @@ def tcm_mod_build_FC_include(fabric_mod_dir_var, fabric_mod_name): buf += "};\n" buf += "\n" buf += "struct " + fabric_mod_name + "_lport {\n" - buf += " /* SCSI protocol the lport is providing */\n" - buf += " u8 lport_proto_id;\n" buf += " /* Binary World Wide unique Port Name for FC Target Lport */\n" buf += " u64 lport_wwpn;\n" buf += " /* ASCII formatted WWPN for FC Target Lport */\n" @@ -105,8 +103,6 @@ def tcm_mod_build_SAS_include(fabric_mod_dir_var, fabric_mod_name): buf += " struct se_portal_group se_tpg;\n" buf += "};\n\n" buf += "struct " + fabric_mod_name + "_tport {\n" - buf += " /* SCSI protocol the tport is providing */\n" - buf += " u8 tport_proto_id;\n" buf += " /* Binary World Wide unique Port Name for SAS Target port */\n" buf += " u64 tport_wwpn;\n" buf += " /* ASCII formatted WWPN for SAS Target port */\n" @@ -150,8 +146,6 @@ def tcm_mod_build_iSCSI_include(fabric_mod_dir_var, fabric_mod_name): buf += " struct se_portal_group se_tpg;\n" buf += "};\n\n" buf += "struct " + fabric_mod_name + "_tport {\n" - buf += " /* SCSI protocol the tport is providing */\n" - buf += " u8 tport_proto_id;\n" buf += " /* ASCII formatted TargetName for IQN */\n" buf += " char tport_name[" + fabric_mod_name.upper() + "_NAMELEN];\n" buf += " /* Returned by " + fabric_mod_name + "_make_tport() */\n" @@ -303,9 +297,6 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += " .get_fabric_name = " + fabric_mod_name + "_get_fabric_name,\n" buf += " .tpg_get_wwn = " + fabric_mod_name + "_get_fabric_wwn,\n" buf += " .tpg_get_tag = " + fabric_mod_name + "_get_tag,\n" - buf += " .tpg_get_pr_transport_id = " + fabric_mod_name + "_get_pr_transport_id,\n" - buf += " .tpg_get_pr_transport_id_len = " + fabric_mod_name + "_get_pr_transport_id_len,\n" - buf += " .tpg_parse_pr_out_transport_id = " + fabric_mod_name + "_parse_pr_out_transport_id,\n" buf += " .tpg_check_demo_mode = " + fabric_mod_name + "_check_false,\n" buf += " .tpg_check_demo_mode_cache = " + fabric_mod_name + "_check_true,\n" buf += " .tpg_check_demo_mode_write_protect = " + fabric_mod_name + "_check_true,\n" @@ -478,118 +469,6 @@ def tcm_mod_dump_fabric_ops(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += "}\n\n" bufi += "u16 " + fabric_mod_name + "_get_tag(struct se_portal_group *);\n" - if re.search('get_pr_transport_id\)\(', fo): - buf += "u32 " + fabric_mod_name + "_get_pr_transport_id(\n" - buf += " struct se_portal_group *se_tpg,\n" - buf += " struct se_node_acl *se_nacl,\n" - buf += " struct t10_pr_registration *pr_reg,\n" - buf += " int *format_code,\n" - buf += " unsigned char *buf)\n" - buf += "{\n" - buf += " struct " + fabric_mod_name + "_tpg *tpg = container_of(se_tpg,\n" - buf += " struct " + fabric_mod_name + "_tpg, se_tpg);\n" - buf += " struct " + fabric_mod_name + "_" + fabric_mod_port + " *" + fabric_mod_port + " = tpg->" + fabric_mod_port + ";\n" - buf += " int ret = 0;\n\n" - buf += " switch (" + fabric_mod_port + "->" + fabric_mod_port + "_proto_id) {\n" - if proto_ident == "FC": - buf += " case SCSI_PROTOCOL_FCP:\n" - buf += " default:\n" - buf += " ret = fc_get_pr_transport_id(se_tpg, se_nacl, pr_reg,\n" - buf += " format_code, buf);\n" - buf += " break;\n" - elif proto_ident == "SAS": - buf += " case SCSI_PROTOCOL_SAS:\n" - buf += " default:\n" - buf += " ret = sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg,\n" - buf += " format_code, buf);\n" - buf += " break;\n" - elif proto_ident == "iSCSI": - buf += " case SCSI_PROTOCOL_ISCSI:\n" - buf += " default:\n" - buf += " ret = iscsi_get_pr_transport_id(se_tpg, se_nacl, pr_reg,\n" - buf += " format_code, buf);\n" - buf += " break;\n" - - buf += " }\n\n" - buf += " return ret;\n" - buf += "}\n\n" - bufi += "u32 " + fabric_mod_name + "_get_pr_transport_id(struct se_portal_group *,\n" - bufi += " struct se_node_acl *, struct t10_pr_registration *,\n" - bufi += " int *, unsigned char *);\n" - - if re.search('get_pr_transport_id_len\)\(', fo): - buf += "u32 " + fabric_mod_name + "_get_pr_transport_id_len(\n" - buf += " struct se_portal_group *se_tpg,\n" - buf += " struct se_node_acl *se_nacl,\n" - buf += " struct t10_pr_registration *pr_reg,\n" - buf += " int *format_code)\n" - buf += "{\n" - buf += " struct " + fabric_mod_name + "_tpg *tpg = container_of(se_tpg,\n" - buf += " struct " + fabric_mod_name + "_tpg, se_tpg);\n" - buf += " struct " + fabric_mod_name + "_" + fabric_mod_port + " *" + fabric_mod_port + " = tpg->" + fabric_mod_port + ";\n" - buf += " int ret = 0;\n\n" - buf += " switch (" + fabric_mod_port + "->" + fabric_mod_port + "_proto_id) {\n" - if proto_ident == "FC": - buf += " case SCSI_PROTOCOL_FCP:\n" - buf += " default:\n" - buf += " ret = fc_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,\n" - buf += " format_code);\n" - buf += " break;\n" - elif proto_ident == "SAS": - buf += " case SCSI_PROTOCOL_SAS:\n" - buf += " default:\n" - buf += " ret = sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,\n" - buf += " format_code);\n" - buf += " break;\n" - elif proto_ident == "iSCSI": - buf += " case SCSI_PROTOCOL_ISCSI:\n" - buf += " default:\n" - buf += " ret = iscsi_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,\n" - buf += " format_code);\n" - buf += " break;\n" - - - buf += " }\n\n" - buf += " return ret;\n" - buf += "}\n\n" - bufi += "u32 " + fabric_mod_name + "_get_pr_transport_id_len(struct se_portal_group *,\n" - bufi += " struct se_node_acl *, struct t10_pr_registration *,\n" - bufi += " int *);\n" - - if re.search('parse_pr_out_transport_id\)\(', fo): - buf += "char *" + fabric_mod_name + "_parse_pr_out_transport_id(\n" - buf += " struct se_portal_group *se_tpg,\n" - buf += " const char *buf,\n" - buf += " u32 *out_tid_len,\n" - buf += " char **port_nexus_ptr)\n" - buf += "{\n" - buf += " struct " + fabric_mod_name + "_tpg *tpg = container_of(se_tpg,\n" - buf += " struct " + fabric_mod_name + "_tpg, se_tpg);\n" - buf += " struct " + fabric_mod_name + "_" + fabric_mod_port + " *" + fabric_mod_port + " = tpg->" + fabric_mod_port + ";\n" - buf += " char *tid = NULL;\n\n" - buf += " switch (" + fabric_mod_port + "->" + fabric_mod_port + "_proto_id) {\n" - if proto_ident == "FC": - buf += " case SCSI_PROTOCOL_FCP:\n" - buf += " default:\n" - buf += " tid = fc_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,\n" - buf += " port_nexus_ptr);\n" - elif proto_ident == "SAS": - buf += " case SCSI_PROTOCOL_SAS:\n" - buf += " default:\n" - buf += " tid = sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,\n" - buf += " port_nexus_ptr);\n" - elif proto_ident == "iSCSI": - buf += " case SCSI_PROTOCOL_ISCSI:\n" - buf += " default:\n" - buf += " tid = iscsi_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,\n" - buf += " port_nexus_ptr);\n" - - buf += " }\n\n" - buf += " return tid;\n" - buf += "}\n\n" - bufi += "char *" + fabric_mod_name + "_parse_pr_out_transport_id(struct se_portal_group *,\n" - bufi += " const char *, u32 *, char **);\n" - if re.search('tpg_get_inst_index\)\(', fo): buf += "u32 " + fabric_mod_name + "_tpg_get_inst_index(struct se_portal_group *se_tpg)\n" buf += "{\n" diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 9213c2de28fc..98e00360f97e 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -3406,42 +3406,6 @@ static u16 srpt_get_tag(struct se_portal_group *tpg) return 1; } -static u32 srpt_get_pr_transport_id(struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl, - struct t10_pr_registration *pr_reg, - int *format_code, unsigned char *buf) -{ - struct srpt_node_acl *nacl; - struct spc_rdma_transport_id *tr_id; - - nacl = container_of(se_nacl, struct srpt_node_acl, nacl); - tr_id = (void *)buf; - tr_id->protocol_identifier = SCSI_TRANSPORTID_PROTOCOLID_SRP; - memcpy(tr_id->i_port_id, nacl->i_port_id, sizeof(tr_id->i_port_id)); - return sizeof(*tr_id); -} - -static u32 srpt_get_pr_transport_id_len(struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl, - struct t10_pr_registration *pr_reg, - int *format_code) -{ - *format_code = 0; - return sizeof(struct spc_rdma_transport_id); -} - -static char *srpt_parse_pr_out_transport_id(struct se_portal_group *se_tpg, - const char *buf, u32 *out_tid_len, - char **port_nexus_ptr) -{ - struct spc_rdma_transport_id *tr_id; - - *port_nexus_ptr = NULL; - *out_tid_len = sizeof(struct spc_rdma_transport_id); - tr_id = (void *)buf; - return (char *)tr_id->i_port_id; -} - static u32 srpt_tpg_get_inst_index(struct se_portal_group *se_tpg) { return 1; @@ -3860,9 +3824,6 @@ static const struct target_core_fabric_ops srpt_template = { .get_fabric_name = srpt_get_fabric_name, .tpg_get_wwn = srpt_get_fabric_wwn, .tpg_get_tag = srpt_get_tag, - .tpg_get_pr_transport_id = srpt_get_pr_transport_id, - .tpg_get_pr_transport_id_len = srpt_get_pr_transport_id_len, - .tpg_parse_pr_out_transport_id = srpt_parse_pr_out_transport_id, .tpg_check_demo_mode = srpt_check_false, .tpg_check_demo_mode_cache = srpt_check_true, .tpg_check_demo_mode_write_protect = srpt_check_true, diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.h b/drivers/infiniband/ulp/srpt/ib_srpt.h index 355f6f5ce8b2..33b2c88b73ba 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.h +++ b/drivers/infiniband/ulp/srpt/ib_srpt.h @@ -422,22 +422,4 @@ struct srpt_node_acl { struct list_head list; }; -/* - * SRP-releated SCSI persistent reservation definitions. - * - * See also SPC4r28, section 7.6.1 (Protocol specific parameters introduction). - * See also SPC4r28, section 7.6.4.5 (TransportID for initiator ports using - * SCSI over an RDMA interface). - */ - -enum { - SCSI_TRANSPORTID_PROTOCOLID_SRP = 4, -}; - -struct spc_rdma_transport_id { - uint8_t protocol_identifier; - uint8_t reserved[7]; - uint8_t i_port_id[16]; -}; - #endif /* IB_SRPT_H */ diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 4566c4649751..bd0f9eb67901 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -206,73 +206,6 @@ static u16 tcm_qla2xxx_get_tag(struct se_portal_group *se_tpg) return tpg->lport_tpgt; } -static u32 tcm_qla2xxx_get_pr_transport_id( - struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl, - struct t10_pr_registration *pr_reg, - int *format_code, - unsigned char *buf) -{ - struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, - struct tcm_qla2xxx_tpg, se_tpg); - struct tcm_qla2xxx_lport *lport = tpg->lport; - int ret = 0; - - switch (lport->lport_proto_id) { - case SCSI_PROTOCOL_FCP: - default: - ret = fc_get_pr_transport_id(se_tpg, se_nacl, pr_reg, - format_code, buf); - break; - } - - return ret; -} - -static u32 tcm_qla2xxx_get_pr_transport_id_len( - struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl, - struct t10_pr_registration *pr_reg, - int *format_code) -{ - struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, - struct tcm_qla2xxx_tpg, se_tpg); - struct tcm_qla2xxx_lport *lport = tpg->lport; - int ret = 0; - - switch (lport->lport_proto_id) { - case SCSI_PROTOCOL_FCP: - default: - ret = fc_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, - format_code); - break; - } - - return ret; -} - -static char *tcm_qla2xxx_parse_pr_out_transport_id( - struct se_portal_group *se_tpg, - const char *buf, - u32 *out_tid_len, - char **port_nexus_ptr) -{ - struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, - struct tcm_qla2xxx_tpg, se_tpg); - struct tcm_qla2xxx_lport *lport = tpg->lport; - char *tid = NULL; - - switch (lport->lport_proto_id) { - case SCSI_PROTOCOL_FCP: - default: - tid = fc_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, - port_nexus_ptr); - break; - } - - return tid; -} - static int tcm_qla2xxx_check_demo_mode(struct se_portal_group *se_tpg) { struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, @@ -1913,9 +1846,6 @@ static const struct target_core_fabric_ops tcm_qla2xxx_ops = { .get_fabric_name = tcm_qla2xxx_get_fabric_name, .tpg_get_wwn = tcm_qla2xxx_get_fabric_wwn, .tpg_get_tag = tcm_qla2xxx_get_tag, - .tpg_get_pr_transport_id = tcm_qla2xxx_get_pr_transport_id, - .tpg_get_pr_transport_id_len = tcm_qla2xxx_get_pr_transport_id_len, - .tpg_parse_pr_out_transport_id = tcm_qla2xxx_parse_pr_out_transport_id, .tpg_check_demo_mode = tcm_qla2xxx_check_demo_mode, .tpg_check_demo_mode_cache = tcm_qla2xxx_check_demo_mode_cache, .tpg_check_demo_mode_write_protect = @@ -1963,9 +1893,6 @@ static const struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = { .get_fabric_name = tcm_qla2xxx_npiv_get_fabric_name, .tpg_get_wwn = tcm_qla2xxx_get_fabric_wwn, .tpg_get_tag = tcm_qla2xxx_get_tag, - .tpg_get_pr_transport_id = tcm_qla2xxx_get_pr_transport_id, - .tpg_get_pr_transport_id_len = tcm_qla2xxx_get_pr_transport_id_len, - .tpg_parse_pr_out_transport_id = tcm_qla2xxx_parse_pr_out_transport_id, .tpg_check_demo_mode = tcm_qla2xxx_check_demo_mode, .tpg_check_demo_mode_cache = tcm_qla2xxx_check_demo_mode_cache, .tpg_check_demo_mode_write_protect = tcm_qla2xxx_check_demo_mode, diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.h b/drivers/scsi/qla2xxx/tcm_qla2xxx.h index 3d805a07061c..3bbf4cb6fd97 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.h +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.h @@ -57,8 +57,6 @@ struct tcm_qla2xxx_fc_loopid { }; struct tcm_qla2xxx_lport { - /* SCSI protocol the lport is providing */ - u8 lport_proto_id; /* Binary World Wide unique Port Name for FC Target Lport */ u64 lport_wwpn; /* Binary World Wide unique Port Name for FC NPIV Target Lport */ diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 9dec9f39139f..bd8af8764f4b 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -1921,9 +1921,6 @@ const struct target_core_fabric_ops iscsi_ops = { .tpg_get_wwn = lio_tpg_get_endpoint_wwn, .tpg_get_tag = lio_tpg_get_tag, .tpg_get_default_depth = lio_tpg_get_default_depth, - .tpg_get_pr_transport_id = iscsi_get_pr_transport_id, - .tpg_get_pr_transport_id_len = iscsi_get_pr_transport_id_len, - .tpg_parse_pr_out_transport_id = iscsi_parse_pr_out_transport_id, .tpg_check_demo_mode = lio_tpg_check_demo_mode, .tpg_check_demo_mode_cache = lio_tpg_check_demo_mode_cache, .tpg_check_demo_mode_write_protect = diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 0eed0209a7f4..b788406977f6 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -542,95 +542,6 @@ static u16 tcm_loop_get_tag(struct se_portal_group *se_tpg) return tl_tpg(se_tpg)->tl_tpgt; } -static u32 tcm_loop_get_pr_transport_id( - struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl, - struct t10_pr_registration *pr_reg, - int *format_code, - unsigned char *buf) -{ - struct tcm_loop_hba *tl_hba = tl_tpg(se_tpg)->tl_hba; - - switch (tl_hba->tl_proto_id) { - case SCSI_PROTOCOL_SAS: - return sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg, - format_code, buf); - case SCSI_PROTOCOL_FCP: - return fc_get_pr_transport_id(se_tpg, se_nacl, pr_reg, - format_code, buf); - case SCSI_PROTOCOL_ISCSI: - return iscsi_get_pr_transport_id(se_tpg, se_nacl, pr_reg, - format_code, buf); - default: - pr_err("Unknown tl_proto_id: 0x%02x, using" - " SAS emulation\n", tl_hba->tl_proto_id); - break; - } - - return sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg, - format_code, buf); -} - -static u32 tcm_loop_get_pr_transport_id_len( - struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl, - struct t10_pr_registration *pr_reg, - int *format_code) -{ - struct tcm_loop_hba *tl_hba = tl_tpg(se_tpg)->tl_hba; - - switch (tl_hba->tl_proto_id) { - case SCSI_PROTOCOL_SAS: - return sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, - format_code); - case SCSI_PROTOCOL_FCP: - return fc_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, - format_code); - case SCSI_PROTOCOL_ISCSI: - return iscsi_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, - format_code); - default: - pr_err("Unknown tl_proto_id: 0x%02x, using" - " SAS emulation\n", tl_hba->tl_proto_id); - break; - } - - return sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, - format_code); -} - -/* - * Used for handling SCSI fabric dependent TransportIDs in SPC-3 and above - * Persistent Reservation SPEC_I_PT=1 and PROUT REGISTER_AND_MOVE operations. - */ -static char *tcm_loop_parse_pr_out_transport_id( - struct se_portal_group *se_tpg, - const char *buf, - u32 *out_tid_len, - char **port_nexus_ptr) -{ - struct tcm_loop_hba *tl_hba = tl_tpg(se_tpg)->tl_hba; - - switch (tl_hba->tl_proto_id) { - case SCSI_PROTOCOL_SAS: - return sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, - port_nexus_ptr); - case SCSI_PROTOCOL_FCP: - return fc_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, - port_nexus_ptr); - case SCSI_PROTOCOL_ISCSI: - return iscsi_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, - port_nexus_ptr); - default: - pr_err("Unknown tl_proto_id: 0x%02x, using" - " SAS emulation\n", tl_hba->tl_proto_id); - break; - } - - return sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, - port_nexus_ptr); -} - /* * Returning (1) here allows for target_core_mod struct se_node_acl to be generated * based upon the incoming fabric dependent SCSI Initiator Port @@ -1332,9 +1243,6 @@ static const struct target_core_fabric_ops loop_ops = { .get_fabric_name = tcm_loop_get_fabric_name, .tpg_get_wwn = tcm_loop_get_endpoint_wwn, .tpg_get_tag = tcm_loop_get_tag, - .tpg_get_pr_transport_id = tcm_loop_get_pr_transport_id, - .tpg_get_pr_transport_id_len = tcm_loop_get_pr_transport_id_len, - .tpg_parse_pr_out_transport_id = tcm_loop_parse_pr_out_transport_id, .tpg_check_demo_mode = tcm_loop_check_demo_mode, .tpg_check_demo_mode_cache = tcm_loop_check_demo_mode_cache, .tpg_check_demo_mode_write_protect = diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index 8acb37fd9ebc..89f172dc8678 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -1832,73 +1832,6 @@ static int sbp_check_stop_free(struct se_cmd *se_cmd) return 1; } -static u32 sbp_get_pr_transport_id( - struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl, - struct t10_pr_registration *pr_reg, - int *format_code, - unsigned char *buf) -{ - int ret; - - /* - * Set PROTOCOL IDENTIFIER to 3h for SBP - */ - buf[0] = SCSI_PROTOCOL_SBP; - /* - * From spc4r17, 7.5.4.4 TransportID for initiator ports using SCSI - * over IEEE 1394 - */ - ret = hex2bin(&buf[8], se_nacl->initiatorname, 8); - if (ret < 0) - pr_debug("sbp transport_id: invalid hex string\n"); - - /* - * The IEEE 1394 Transport ID is a hardcoded 24-byte length - */ - return 24; -} - -static u32 sbp_get_pr_transport_id_len( - struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl, - struct t10_pr_registration *pr_reg, - int *format_code) -{ - *format_code = 0; - /* - * From spc4r17, 7.5.4.4 TransportID for initiator ports using SCSI - * over IEEE 1394 - * - * The SBP Transport ID is a hardcoded 24-byte length - */ - return 24; -} - -/* - * Used for handling SCSI fabric dependent TransportIDs in SPC-3 and above - * Persistent Reservation SPEC_I_PT=1 and PROUT REGISTER_AND_MOVE operations. - */ -static char *sbp_parse_pr_out_transport_id( - struct se_portal_group *se_tpg, - const char *buf, - u32 *out_tid_len, - char **port_nexus_ptr) -{ - /* - * Assume the FORMAT CODE 00b from spc4r17, 7.5.4.4 TransportID - * for initiator ports using SCSI over SBP Serial SCSI Protocol - * - * The TransportID for a IEEE 1394 Initiator Port is of fixed size of - * 24 bytes, and IEEE 1394 does not contain a I_T nexus identifier, - * so we return the **port_nexus_ptr set to NULL. - */ - *port_nexus_ptr = NULL; - *out_tid_len = 24; - - return (char *)&buf[8]; -} - static int sbp_count_se_tpg_luns(struct se_portal_group *tpg) { int i, count = 0; @@ -2432,9 +2365,6 @@ static const struct target_core_fabric_ops sbp_ops = { .get_fabric_name = sbp_get_fabric_name, .tpg_get_wwn = sbp_get_fabric_wwn, .tpg_get_tag = sbp_get_tag, - .tpg_get_pr_transport_id = sbp_get_pr_transport_id, - .tpg_get_pr_transport_id_len = sbp_get_pr_transport_id_len, - .tpg_parse_pr_out_transport_id = sbp_parse_pr_out_transport_id, .tpg_check_demo_mode = sbp_check_true, .tpg_check_demo_mode_cache = sbp_check_true, .tpg_check_demo_mode_write_protect = sbp_check_false, diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 21c9f7d79d5e..5e2649fc6919 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -326,14 +326,6 @@ static int target_fabric_tf_ops_check(const struct target_core_fabric_ops *tfo) pr_err("Missing tfo->tpg_get_tag()\n"); return -EINVAL; } - if (!tfo->tpg_get_pr_transport_id) { - pr_err("Missing tfo->tpg_get_pr_transport_id()\n"); - return -EINVAL; - } - if (!tfo->tpg_get_pr_transport_id_len) { - pr_err("Missing tfo->tpg_get_pr_transport_id_len()\n"); - return -EINVAL; - } if (!tfo->tpg_check_demo_mode) { pr_err("Missing tfo->tpg_check_demo_mode()\n"); return -EINVAL; diff --git a/drivers/target/target_core_fabric_lib.c b/drivers/target/target_core_fabric_lib.c index 6fed14adbe61..89720b2f37c2 100644 --- a/drivers/target/target_core_fabric_lib.c +++ b/drivers/target/target_core_fabric_lib.c @@ -24,6 +24,11 @@ * ******************************************************************************/ +/* + * See SPC4, section 7.5 "Protocol specific parameters" for details + * on the formats implemented in this file. + */ + #include #include #include @@ -39,103 +44,26 @@ #include "target_core_internal.h" #include "target_core_pr.h" -/* - * Handlers for Serial Attached SCSI (SAS) - */ -u32 sas_get_pr_transport_id( - struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl, - struct t10_pr_registration *pr_reg, + +static int sas_get_pr_transport_id( + struct se_node_acl *nacl, int *format_code, unsigned char *buf) { - unsigned char *ptr; int ret; - /* - * Set PROTOCOL IDENTIFIER to 6h for SAS - */ - buf[0] = 0x06; - /* - * From spc4r17, 7.5.4.7 TransportID for initiator ports using SCSI - * over SAS Serial SCSI Protocol - */ - ptr = &se_nacl->initiatorname[4]; /* Skip over 'naa. prefix */ - - ret = hex2bin(&buf[4], ptr, 8); - if (ret < 0) - pr_debug("sas transport_id: invalid hex string\n"); - - /* - * The SAS Transport ID is a hardcoded 24-byte length - */ - return 24; -} -EXPORT_SYMBOL(sas_get_pr_transport_id); - -u32 sas_get_pr_transport_id_len( - struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl, - struct t10_pr_registration *pr_reg, - int *format_code) -{ - *format_code = 0; - /* - * From spc4r17, 7.5.4.7 TransportID for initiator ports using SCSI - * over SAS Serial SCSI Protocol - * - * The SAS Transport ID is a hardcoded 24-byte length - */ - return 24; -} -EXPORT_SYMBOL(sas_get_pr_transport_id_len); - -/* - * Used for handling SCSI fabric dependent TransportIDs in SPC-3 and above - * Persistent Reservation SPEC_I_PT=1 and PROUT REGISTER_AND_MOVE operations. - */ -char *sas_parse_pr_out_transport_id( - struct se_portal_group *se_tpg, - const char *buf, - u32 *out_tid_len, - char **port_nexus_ptr) -{ - /* - * Assume the FORMAT CODE 00b from spc4r17, 7.5.4.7 TransportID - * for initiator ports using SCSI over SAS Serial SCSI Protocol - * - * The TransportID for a SAS Initiator Port is of fixed size of - * 24 bytes, and SAS does not contain a I_T nexus identifier, - * so we return the **port_nexus_ptr set to NULL. - */ - *port_nexus_ptr = NULL; - *out_tid_len = 24; - - return (char *)&buf[4]; -} -EXPORT_SYMBOL(sas_parse_pr_out_transport_id); + /* Skip over 'naa. prefix */ + ret = hex2bin(&buf[4], &nacl->initiatorname[4], 8); + if (ret) { + pr_debug("%s: invalid hex string\n", __func__); + return ret; + } -/* - * Handlers for Fibre Channel Protocol (FCP) - */ -u32 fc_get_pr_transport_id_len( - struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl, - struct t10_pr_registration *pr_reg, - int *format_code) -{ - *format_code = 0; - /* - * The FC Transport ID is a hardcoded 24-byte length - */ return 24; } -EXPORT_SYMBOL(fc_get_pr_transport_id_len); -u32 fc_get_pr_transport_id( - struct se_portal_group *se_tpg, +static int fc_get_pr_transport_id( struct se_node_acl *se_nacl, - struct t10_pr_registration *pr_reg, int *format_code, unsigned char *buf) { @@ -144,24 +72,20 @@ u32 fc_get_pr_transport_id( u32 off = 8; /* - * PROTOCOL IDENTIFIER is 0h for FCP-2 - * - * From spc4r17, 7.5.4.2 TransportID for initiator ports using - * SCSI over Fibre Channel - * * We convert the ASCII formatted N Port name into a binary * encoded TransportID. */ ptr = &se_nacl->initiatorname[0]; - for (i = 0; i < 24; ) { if (!strncmp(&ptr[i], ":", 1)) { i++; continue; } ret = hex2bin(&buf[off++], &ptr[i], 1); - if (ret < 0) - pr_debug("fc transport_id: invalid hex string\n"); + if (ret < 0) { + pr_debug("%s: invalid hex string\n", __func__); + return ret; + } i += 2; } /* @@ -169,31 +93,52 @@ u32 fc_get_pr_transport_id( */ return 24; } -EXPORT_SYMBOL(fc_get_pr_transport_id); -char *fc_parse_pr_out_transport_id( - struct se_portal_group *se_tpg, - const char *buf, - u32 *out_tid_len, - char **port_nexus_ptr) +static int sbp_get_pr_transport_id( + struct se_node_acl *nacl, + int *format_code, + unsigned char *buf) { - /* - * The TransportID for a FC N Port is of fixed size of - * 24 bytes, and FC does not contain a I_T nexus identifier, - * so we return the **port_nexus_ptr set to NULL. - */ - *port_nexus_ptr = NULL; - *out_tid_len = 24; + int ret; + + ret = hex2bin(&buf[8], nacl->initiatorname, 8); + if (ret) { + pr_debug("%s: invalid hex string\n", __func__); + return ret; + } - return (char *)&buf[8]; + return 24; } -EXPORT_SYMBOL(fc_parse_pr_out_transport_id); -/* - * Handlers for Internet Small Computer Systems Interface (iSCSI) - */ -u32 iscsi_get_pr_transport_id( - struct se_portal_group *se_tpg, +static int srp_get_pr_transport_id( + struct se_node_acl *nacl, + int *format_code, + unsigned char *buf) +{ + const char *p; + unsigned len, count, leading_zero_bytes; + int rc; + + p = nacl->initiatorname; + if (strncasecmp(p, "0x", 2) == 0) + p += 2; + len = strlen(p); + if (len % 2) + return -EINVAL; + + count = min(len / 2, 16U); + leading_zero_bytes = 16 - count; + memset(buf + 8, 0, leading_zero_bytes); + rc = hex2bin(buf + 8 + leading_zero_bytes, p, count); + if (rc < 0) { + pr_debug("hex2bin failed for %s: %d\n", __func__, rc); + return rc; + } + + return 24; +} + +static int iscsi_get_pr_transport_id( struct se_node_acl *se_nacl, struct t10_pr_registration *pr_reg, int *format_code, @@ -203,10 +148,6 @@ u32 iscsi_get_pr_transport_id( u16 len = 0; spin_lock_irq(&se_nacl->nacl_sess_lock); - /* - * Set PROTOCOL IDENTIFIER to 5h for iSCSI - */ - buf[0] = 0x05; /* * From spc4r17 Section 7.5.4.6: TransportID for initiator * ports using SCSI over iSCSI. @@ -286,10 +227,8 @@ u32 iscsi_get_pr_transport_id( return len; } -EXPORT_SYMBOL(iscsi_get_pr_transport_id); -u32 iscsi_get_pr_transport_id_len( - struct se_portal_group *se_tpg, +static int iscsi_get_pr_transport_id_len( struct se_node_acl *se_nacl, struct t10_pr_registration *pr_reg, int *format_code) @@ -332,9 +271,8 @@ u32 iscsi_get_pr_transport_id_len( return len; } -EXPORT_SYMBOL(iscsi_get_pr_transport_id_len); -char *iscsi_parse_pr_out_transport_id( +static char *iscsi_parse_pr_out_transport_id( struct se_portal_group *se_tpg, const char *buf, u32 *out_tid_len, @@ -421,4 +359,79 @@ char *iscsi_parse_pr_out_transport_id( return (char *)&buf[4]; } -EXPORT_SYMBOL(iscsi_parse_pr_out_transport_id); + +int target_get_pr_transport_id_len(struct se_node_acl *nacl, + struct t10_pr_registration *pr_reg, int *format_code) +{ + switch (nacl->se_tpg->proto_id) { + case SCSI_PROTOCOL_FCP: + case SCSI_PROTOCOL_SBP: + case SCSI_PROTOCOL_SRP: + case SCSI_PROTOCOL_SAS: + break; + case SCSI_PROTOCOL_ISCSI: + return iscsi_get_pr_transport_id_len(nacl, pr_reg, format_code); + default: + pr_err("Unknown proto_id: 0x%02x\n", nacl->se_tpg->proto_id); + return -EINVAL; + } + + /* + * Most transports use a fixed length 24 byte identifier. + */ + *format_code = 0; + return 24; +} + +int target_get_pr_transport_id(struct se_node_acl *nacl, + struct t10_pr_registration *pr_reg, int *format_code, + unsigned char *buf) +{ + switch (nacl->se_tpg->proto_id) { + case SCSI_PROTOCOL_SAS: + return sas_get_pr_transport_id(nacl, format_code, buf); + case SCSI_PROTOCOL_SBP: + return sbp_get_pr_transport_id(nacl, format_code, buf); + case SCSI_PROTOCOL_SRP: + return srp_get_pr_transport_id(nacl, format_code, buf); + case SCSI_PROTOCOL_FCP: + return fc_get_pr_transport_id(nacl, format_code, buf); + case SCSI_PROTOCOL_ISCSI: + return iscsi_get_pr_transport_id(nacl, pr_reg, format_code, + buf); + default: + pr_err("Unknown proto_id: 0x%02x\n", nacl->se_tpg->proto_id); + return -EINVAL; + } +} + +const char *target_parse_pr_out_transport_id(struct se_portal_group *tpg, + const char *buf, u32 *out_tid_len, char **port_nexus_ptr) +{ + u32 offset; + + switch (tpg->proto_id) { + case SCSI_PROTOCOL_SAS: + /* + * Assume the FORMAT CODE 00b from spc4r17, 7.5.4.7 TransportID + * for initiator ports using SCSI over SAS Serial SCSI Protocol. + */ + offset = 4; + break; + case SCSI_PROTOCOL_SBP: + case SCSI_PROTOCOL_SRP: + case SCSI_PROTOCOL_FCP: + offset = 8; + break; + case SCSI_PROTOCOL_ISCSI: + return iscsi_parse_pr_out_transport_id(tpg, buf, out_tid_len, + port_nexus_ptr); + default: + pr_err("Unknown proto_id: 0x%02x\n", tpg->proto_id); + return NULL; + } + + *port_nexus_ptr = NULL; + *out_tid_len = 24; + return buf + offset; +} diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index 058ca71cda81..d0344ad9b0d8 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -38,6 +38,15 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name); int target_configure_device(struct se_device *dev); void target_free_device(struct se_device *); +/* target_core_fabric_lib.c */ +int target_get_pr_transport_id_len(struct se_node_acl *nacl, + struct t10_pr_registration *pr_reg, int *format_code); +int target_get_pr_transport_id(struct se_node_acl *nacl, + struct t10_pr_registration *pr_reg, int *format_code, + unsigned char *buf); +const char *target_parse_pr_out_transport_id(struct se_portal_group *tpg, + const char *buf, u32 *out_tid_len, char **port_nexus_ptr); + /* target_core_hba.c */ struct se_hba *core_alloc_hba(const char *, u32, u32); int core_delete_hba(struct se_hba *); diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 23c065f83a56..d396b3b87025 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -1445,9 +1445,8 @@ core_scsi3_decode_spec_i_port( struct t10_pr_registration *pr_reg_tmp, *pr_reg_tmp_safe; LIST_HEAD(tid_dest_list); struct pr_transport_id_holder *tidh_new, *tidh, *tidh_tmp; - const struct target_core_fabric_ops *tmp_tf_ops; - unsigned char *buf; - unsigned char *ptr, *i_str = NULL, proto_ident; + unsigned char *buf, *ptr, proto_ident; + const unsigned char *i_str; char *iport_ptr = NULL, i_buf[PR_REG_ISID_ID_LEN]; sense_reason_t ret; u32 tpdl, tid_len = 0; @@ -1533,11 +1532,7 @@ core_scsi3_decode_spec_i_port( tmp_tpg = tmp_port->sep_tpg; if (!tmp_tpg) continue; - tmp_tf_ops = tmp_tpg->se_tpg_tfo; - if (!tmp_tf_ops) - continue; - if (!tmp_tf_ops->tpg_parse_pr_out_transport_id) - continue; + /* * Look for the matching proto_ident provided by * the received TransportID @@ -1546,9 +1541,8 @@ core_scsi3_decode_spec_i_port( continue; dest_rtpi = tmp_port->sep_rtpi; - i_str = tmp_tf_ops->tpg_parse_pr_out_transport_id( - tmp_tpg, (const char *)ptr, &tid_len, - &iport_ptr); + i_str = target_parse_pr_out_transport_id(tmp_tpg, + (const char *)ptr, &tid_len, &iport_ptr); if (!i_str) continue; @@ -3105,7 +3099,7 @@ core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key, struct t10_pr_registration *pr_reg, *pr_res_holder, *dest_pr_reg; struct t10_reservation *pr_tmpl = &dev->t10_pr; unsigned char *buf; - unsigned char *initiator_str; + const unsigned char *initiator_str; char *iport_ptr = NULL, i_buf[PR_REG_ISID_ID_LEN]; u32 tid_len, tmp_tid_len; int new_reg = 0, type, scope, matching_iname; @@ -3237,14 +3231,7 @@ core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key, ret = TCM_INVALID_PARAMETER_LIST; goto out; } - if (dest_tf_ops->tpg_parse_pr_out_transport_id == NULL) { - pr_err("SPC-3 PR REGISTER_AND_MOVE: Fabric does not" - " containg a valid tpg_parse_pr_out_transport_id" - " function pointer\n"); - ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - goto out; - } - initiator_str = dest_tf_ops->tpg_parse_pr_out_transport_id(dest_se_tpg, + initiator_str = target_parse_pr_out_transport_id(dest_se_tpg, (const char *)&buf[24], &tmp_tid_len, &iport_ptr); if (!initiator_str) { pr_err("SPC-3 PR REGISTER_AND_MOVE: Unable to locate" @@ -3881,9 +3868,10 @@ core_scsi3_pri_read_full_status(struct se_cmd *cmd) struct t10_pr_registration *pr_reg, *pr_reg_tmp; struct t10_reservation *pr_tmpl = &dev->t10_pr; unsigned char *buf; - u32 add_desc_len = 0, add_len = 0, desc_len, exp_desc_len; + u32 add_desc_len = 0, add_len = 0; u32 off = 8; /* off into first Full Status descriptor */ int format_code = 0, pr_res_type = 0, pr_res_scope = 0; + int exp_desc_len, desc_len; bool all_reg = false; if (cmd->data_length < 8) { @@ -3928,10 +3916,10 @@ core_scsi3_pri_read_full_status(struct se_cmd *cmd) * Determine expected length of $FABRIC_MOD specific * TransportID full status descriptor.. */ - exp_desc_len = se_tpg->se_tpg_tfo->tpg_get_pr_transport_id_len( - se_tpg, se_nacl, pr_reg, &format_code); - - if ((exp_desc_len + add_len) > cmd->data_length) { + exp_desc_len = target_get_pr_transport_id_len(se_nacl, pr_reg, + &format_code); + if (exp_desc_len < 0 || + exp_desc_len + add_len > cmd->data_length) { pr_warn("SPC-3 PRIN READ_FULL_STATUS ran" " out of buffer: %d\n", cmd->data_length); spin_lock(&pr_tmpl->registration_lock); @@ -3995,14 +3983,19 @@ core_scsi3_pri_read_full_status(struct se_cmd *cmd) } else off += 2; /* Skip over RELATIVE TARGET PORT IDENTIFIER */ + buf[off+4] = se_tpg->proto_id; + /* - * Now, have the $FABRIC_MOD fill in the protocol identifier + * Now, have the $FABRIC_MOD fill in the transport ID. */ - desc_len = se_tpg->se_tpg_tfo->tpg_get_pr_transport_id(se_tpg, - se_nacl, pr_reg, &format_code, &buf[off+4]); + desc_len = target_get_pr_transport_id(se_nacl, pr_reg, + &format_code, &buf[off+4]); spin_lock(&pr_tmpl->registration_lock); atomic_dec_mb(&pr_reg->pr_res_holders); + + if (desc_len < 0) + break; /* * Set the ADDITIONAL DESCRIPTOR LENGTH */ diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c index fabc7bacf693..6ad7404b7dd1 100644 --- a/drivers/target/tcm_fc/tfc_conf.c +++ b/drivers/target/tcm_fc/tfc_conf.c @@ -454,9 +454,6 @@ static const struct target_core_fabric_ops ft_fabric_ops = { .get_fabric_name = ft_get_fabric_name, .tpg_get_wwn = ft_get_fabric_wwn, .tpg_get_tag = ft_get_tag, - .tpg_get_pr_transport_id = fc_get_pr_transport_id, - .tpg_get_pr_transport_id_len = fc_get_pr_transport_id_len, - .tpg_parse_pr_out_transport_id = fc_parse_pr_out_transport_id, .tpg_check_demo_mode = ft_check_false, .tpg_check_demo_mode_cache = ft_check_false, .tpg_check_demo_mode_write_protect = ft_check_false, diff --git a/drivers/usb/gadget/legacy/tcm_usb_gadget.c b/drivers/usb/gadget/legacy/tcm_usb_gadget.c index d6b03178262f..77cdbb56e1d5 100644 --- a/drivers/usb/gadget/legacy/tcm_usb_gadget.c +++ b/drivers/usb/gadget/legacy/tcm_usb_gadget.c @@ -1290,72 +1290,6 @@ static u16 usbg_get_tag(struct se_portal_group *se_tpg) return tpg->tport_tpgt; } -static u32 usbg_get_pr_transport_id( - struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl, - struct t10_pr_registration *pr_reg, - int *format_code, - unsigned char *buf) -{ - struct usbg_tpg *tpg = container_of(se_tpg, - struct usbg_tpg, se_tpg); - struct usbg_tport *tport = tpg->tport; - int ret = 0; - - switch (tport->tport_proto_id) { - case SCSI_PROTOCOL_SAS: - default: - ret = sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg, - format_code, buf); - break; - } - - return ret; -} - -static u32 usbg_get_pr_transport_id_len( - struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl, - struct t10_pr_registration *pr_reg, - int *format_code) -{ - struct usbg_tpg *tpg = container_of(se_tpg, - struct usbg_tpg, se_tpg); - struct usbg_tport *tport = tpg->tport; - int ret = 0; - - switch (tport->tport_proto_id) { - case SCSI_PROTOCOL_SAS: - default: - ret = sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, - format_code); - break; - } - - return ret; -} - -static char *usbg_parse_pr_out_transport_id( - struct se_portal_group *se_tpg, - const char *buf, - u32 *out_tid_len, - char **port_nexus_ptr) -{ - struct usbg_tpg *tpg = container_of(se_tpg, - struct usbg_tpg, se_tpg); - struct usbg_tport *tport = tpg->tport; - char *tid = NULL; - - switch (tport->tport_proto_id) { - case SCSI_PROTOCOL_SAS: - default: - tid = sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, - port_nexus_ptr); - } - - return tid; -} - static u32 usbg_tpg_get_inst_index(struct se_portal_group *se_tpg) { return 1; @@ -1491,8 +1425,12 @@ static struct se_portal_group *usbg_make_tpg( tpg->tport = tport; tpg->tport_tpgt = tpgt; + /* + * SPC doesn't assign a protocol identifier for USB-SCSI, so we + * pretend to be SAS.. + */ ret = core_tpg_register(&usbg_ops, wwn, &tpg->se_tpg, - tport->tport_proto_id); + SCSI_PROTOCOL_SAS); if (ret < 0) { destroy_workqueue(tpg->workqueue); kfree(tpg); @@ -1788,9 +1726,6 @@ static const struct target_core_fabric_ops usbg_ops = { .get_fabric_name = usbg_get_fabric_name, .tpg_get_wwn = usbg_get_fabric_wwn, .tpg_get_tag = usbg_get_tag, - .tpg_get_pr_transport_id = usbg_get_pr_transport_id, - .tpg_get_pr_transport_id_len = usbg_get_pr_transport_id_len, - .tpg_parse_pr_out_transport_id = usbg_parse_pr_out_transport_id, .tpg_check_demo_mode = usbg_check_true, .tpg_check_demo_mode_cache = usbg_check_false, .tpg_check_demo_mode_write_protect = usbg_check_false, diff --git a/drivers/usb/gadget/legacy/tcm_usb_gadget.h b/drivers/usb/gadget/legacy/tcm_usb_gadget.h index b254aec521da..4c1c22a964b4 100644 --- a/drivers/usb/gadget/legacy/tcm_usb_gadget.h +++ b/drivers/usb/gadget/legacy/tcm_usb_gadget.h @@ -44,8 +44,6 @@ struct usbg_tpg { }; struct usbg_tport { - /* SCSI protocol the tport is providing */ - u8 tport_proto_id; /* Binary World Wide unique Port Name for SAS Target port */ u64 tport_wwpn; /* ASCII formatted WWPN for SAS Target port */ diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index 022860ccd008..db9f4b474214 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -304,97 +304,6 @@ static u16 vhost_scsi_get_tpgt(struct se_portal_group *se_tpg) return tpg->tport_tpgt; } -static u32 -vhost_scsi_get_pr_transport_id(struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl, - struct t10_pr_registration *pr_reg, - int *format_code, - unsigned char *buf) -{ - struct vhost_scsi_tpg *tpg = container_of(se_tpg, - struct vhost_scsi_tpg, se_tpg); - struct vhost_scsi_tport *tport = tpg->tport; - - switch (tport->tport_proto_id) { - case SCSI_PROTOCOL_SAS: - return sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg, - format_code, buf); - case SCSI_PROTOCOL_FCP: - return fc_get_pr_transport_id(se_tpg, se_nacl, pr_reg, - format_code, buf); - case SCSI_PROTOCOL_ISCSI: - return iscsi_get_pr_transport_id(se_tpg, se_nacl, pr_reg, - format_code, buf); - default: - pr_err("Unknown tport_proto_id: 0x%02x, using" - " SAS emulation\n", tport->tport_proto_id); - break; - } - - return sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg, - format_code, buf); -} - -static u32 -vhost_scsi_get_pr_transport_id_len(struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl, - struct t10_pr_registration *pr_reg, - int *format_code) -{ - struct vhost_scsi_tpg *tpg = container_of(se_tpg, - struct vhost_scsi_tpg, se_tpg); - struct vhost_scsi_tport *tport = tpg->tport; - - switch (tport->tport_proto_id) { - case SCSI_PROTOCOL_SAS: - return sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, - format_code); - case SCSI_PROTOCOL_FCP: - return fc_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, - format_code); - case SCSI_PROTOCOL_ISCSI: - return iscsi_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, - format_code); - default: - pr_err("Unknown tport_proto_id: 0x%02x, using" - " SAS emulation\n", tport->tport_proto_id); - break; - } - - return sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, - format_code); -} - -static char * -vhost_scsi_parse_pr_out_transport_id(struct se_portal_group *se_tpg, - const char *buf, - u32 *out_tid_len, - char **port_nexus_ptr) -{ - struct vhost_scsi_tpg *tpg = container_of(se_tpg, - struct vhost_scsi_tpg, se_tpg); - struct vhost_scsi_tport *tport = tpg->tport; - - switch (tport->tport_proto_id) { - case SCSI_PROTOCOL_SAS: - return sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, - port_nexus_ptr); - case SCSI_PROTOCOL_FCP: - return fc_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, - port_nexus_ptr); - case SCSI_PROTOCOL_ISCSI: - return iscsi_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, - port_nexus_ptr); - default: - pr_err("Unknown tport_proto_id: 0x%02x, using" - " SAS emulation\n", tport->tport_proto_id); - break; - } - - return sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, - port_nexus_ptr); -} - static int vhost_scsi_check_prot_fabric_only(struct se_portal_group *se_tpg) { struct vhost_scsi_tpg *tpg = container_of(se_tpg, @@ -2224,9 +2133,6 @@ static struct target_core_fabric_ops vhost_scsi_ops = { .get_fabric_name = vhost_scsi_get_fabric_name, .tpg_get_wwn = vhost_scsi_get_fabric_wwn, .tpg_get_tag = vhost_scsi_get_tpgt, - .tpg_get_pr_transport_id = vhost_scsi_get_pr_transport_id, - .tpg_get_pr_transport_id_len = vhost_scsi_get_pr_transport_id_len, - .tpg_parse_pr_out_transport_id = vhost_scsi_parse_pr_out_transport_id, .tpg_check_demo_mode = vhost_scsi_check_true, .tpg_check_demo_mode_cache = vhost_scsi_check_true, .tpg_check_demo_mode_write_protect = vhost_scsi_check_false, diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index 8bf9448bd7fd..10c71a5616fa 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -1270,97 +1270,6 @@ static u16 scsiback_get_tag(struct se_portal_group *se_tpg) return tpg->tport_tpgt; } -static u32 -scsiback_get_pr_transport_id(struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl, - struct t10_pr_registration *pr_reg, - int *format_code, - unsigned char *buf) -{ - struct scsiback_tpg *tpg = container_of(se_tpg, - struct scsiback_tpg, se_tpg); - struct scsiback_tport *tport = tpg->tport; - - switch (tport->tport_proto_id) { - case SCSI_PROTOCOL_SAS: - return sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg, - format_code, buf); - case SCSI_PROTOCOL_FCP: - return fc_get_pr_transport_id(se_tpg, se_nacl, pr_reg, - format_code, buf); - case SCSI_PROTOCOL_ISCSI: - return iscsi_get_pr_transport_id(se_tpg, se_nacl, pr_reg, - format_code, buf); - default: - pr_err("Unknown tport_proto_id: 0x%02x, using SAS emulation\n", - tport->tport_proto_id); - break; - } - - return sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg, - format_code, buf); -} - -static u32 -scsiback_get_pr_transport_id_len(struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl, - struct t10_pr_registration *pr_reg, - int *format_code) -{ - struct scsiback_tpg *tpg = container_of(se_tpg, - struct scsiback_tpg, se_tpg); - struct scsiback_tport *tport = tpg->tport; - - switch (tport->tport_proto_id) { - case SCSI_PROTOCOL_SAS: - return sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, - format_code); - case SCSI_PROTOCOL_FCP: - return fc_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, - format_code); - case SCSI_PROTOCOL_ISCSI: - return iscsi_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, - format_code); - default: - pr_err("Unknown tport_proto_id: 0x%02x, using SAS emulation\n", - tport->tport_proto_id); - break; - } - - return sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, - format_code); -} - -static char * -scsiback_parse_pr_out_transport_id(struct se_portal_group *se_tpg, - const char *buf, - u32 *out_tid_len, - char **port_nexus_ptr) -{ - struct scsiback_tpg *tpg = container_of(se_tpg, - struct scsiback_tpg, se_tpg); - struct scsiback_tport *tport = tpg->tport; - - switch (tport->tport_proto_id) { - case SCSI_PROTOCOL_SAS: - return sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, - port_nexus_ptr); - case SCSI_PROTOCOL_FCP: - return fc_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, - port_nexus_ptr); - case SCSI_PROTOCOL_ISCSI: - return iscsi_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, - port_nexus_ptr); - default: - pr_err("Unknown tport_proto_id: 0x%02x, using SAS emulation\n", - tport->tport_proto_id); - break; - } - - return sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, - port_nexus_ptr); -} - static struct se_wwn * scsiback_make_tport(struct target_fabric_configfs *tf, struct config_group *group, @@ -1909,9 +1818,6 @@ static const struct target_core_fabric_ops scsiback_ops = { .get_fabric_name = scsiback_get_fabric_name, .tpg_get_wwn = scsiback_get_fabric_wwn, .tpg_get_tag = scsiback_get_tag, - .tpg_get_pr_transport_id = scsiback_get_pr_transport_id, - .tpg_get_pr_transport_id_len = scsiback_get_pr_transport_id_len, - .tpg_parse_pr_out_transport_id = scsiback_parse_pr_out_transport_id, .tpg_check_demo_mode = scsiback_check_true, .tpg_check_demo_mode_cache = scsiback_check_true, .tpg_check_demo_mode_write_protect = scsiback_check_false, diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index 495606382546..a420f434c6c5 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -9,15 +9,6 @@ struct target_core_fabric_ops { char *(*tpg_get_wwn)(struct se_portal_group *); u16 (*tpg_get_tag)(struct se_portal_group *); u32 (*tpg_get_default_depth)(struct se_portal_group *); - u32 (*tpg_get_pr_transport_id)(struct se_portal_group *, - struct se_node_acl *, - struct t10_pr_registration *, int *, - unsigned char *); - u32 (*tpg_get_pr_transport_id_len)(struct se_portal_group *, - struct se_node_acl *, - struct t10_pr_registration *, int *); - char *(*tpg_parse_pr_out_transport_id)(struct se_portal_group *, - const char *, u32 *, char **); int (*tpg_check_demo_mode)(struct se_portal_group *); int (*tpg_check_demo_mode_cache)(struct se_portal_group *); int (*tpg_check_demo_mode_write_protect)(struct se_portal_group *); @@ -177,30 +168,6 @@ int core_tpg_register(const struct target_core_fabric_ops *, struct se_wwn *, struct se_portal_group *, int); int core_tpg_deregister(struct se_portal_group *); -/* SAS helpers */ -u32 sas_get_pr_transport_id(struct se_portal_group *, struct se_node_acl *, - struct t10_pr_registration *, int *, unsigned char *); -u32 sas_get_pr_transport_id_len(struct se_portal_group *, struct se_node_acl *, - struct t10_pr_registration *, int *); -char *sas_parse_pr_out_transport_id(struct se_portal_group *, const char *, - u32 *, char **); - -/* FC helpers */ -u32 fc_get_pr_transport_id(struct se_portal_group *, struct se_node_acl *, - struct t10_pr_registration *, int *, unsigned char *); -u32 fc_get_pr_transport_id_len(struct se_portal_group *, struct se_node_acl *, - struct t10_pr_registration *, int *); -char *fc_parse_pr_out_transport_id(struct se_portal_group *, const char *, - u32 *, char **); - -/* iSCSI helpers */ -u32 iscsi_get_pr_transport_id(struct se_portal_group *, struct se_node_acl *, - struct t10_pr_registration *, int *, unsigned char *); -u32 iscsi_get_pr_transport_id_len(struct se_portal_group *, struct se_node_acl *, - struct t10_pr_registration *, int *); -char *iscsi_parse_pr_out_transport_id(struct se_portal_group *, const char *, - u32 *, char **); - /* * The LIO target core uses DMA_TO_DEVICE to mean that data is going * to the target (eg handling a WRITE) and DMA_FROM_DEVICE to mean -- cgit v1.2.3-70-g09d2 From 649ee05499d1257a3af0e10d961a1c52d9ef95b7 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 14 Apr 2015 13:26:44 +0200 Subject: target: Move task tag into struct se_cmd + support 64-bit tags Simplify target core and target drivers by storing the task tag a.k.a. command identifier inside struct se_cmd. For several transports (e.g. SRP) tags are 64 bits wide. Hence add support for 64-bit tags. (Fix core_tmr_abort_task conversion spec warnings - nab) (Fix up usb-gadget to use 16-bit tags - HCH + bart) Signed-off-by: Bart Van Assche Cc: Christoph Hellwig Cc: Andy Grover Cc: Sagi Grimberg Cc: Cc: Felipe Balbi Cc: Michael S. Tsirkin Cc: Juergen Gross Signed-off-by: Nicholas Bellinger --- Documentation/target/tcm_mod_builder.py | 8 ----- drivers/infiniband/ulp/srpt/ib_srpt.c | 27 +++++---------- drivers/infiniband/ulp/srpt/ib_srpt.h | 1 - drivers/scsi/qla2xxx/qla_target.c | 52 ++++++++++++---------------- drivers/scsi/qla2xxx/qla_target.h | 1 - drivers/scsi/qla2xxx/tcm_qla2xxx.c | 15 -------- drivers/target/iscsi/iscsi_target.c | 2 ++ drivers/target/iscsi/iscsi_target_configfs.c | 9 ----- drivers/target/loopback/tcm_loop.c | 10 +----- drivers/target/sbp/sbp_target.c | 12 ++----- drivers/target/target_core_configfs.c | 4 --- drivers/target/target_core_tmr.c | 21 +++++------ drivers/target/target_core_transport.c | 41 +++++++++++----------- drivers/target/target_core_xcopy.c | 7 +--- drivers/target/tcm_fc/tcm_fc.h | 1 - drivers/target/tcm_fc/tfc_cmd.c | 10 +----- drivers/target/tcm_fc/tfc_conf.c | 1 - drivers/usb/gadget/legacy/tcm_usb_gadget.c | 15 ++------ drivers/vhost/scsi.c | 7 +--- drivers/xen/xen-scsiback.c | 10 +----- include/target/target_core_base.h | 3 +- include/target/target_core_fabric.h | 1 - 22 files changed, 76 insertions(+), 182 deletions(-) (limited to 'drivers') diff --git a/Documentation/target/tcm_mod_builder.py b/Documentation/target/tcm_mod_builder.py index 0dbd70cccde1..71e1f5863310 100755 --- a/Documentation/target/tcm_mod_builder.py +++ b/Documentation/target/tcm_mod_builder.py @@ -310,7 +310,6 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += " .write_pending = " + fabric_mod_name + "_write_pending,\n" buf += " .write_pending_status = " + fabric_mod_name + "_write_pending_status,\n" buf += " .set_default_node_attributes = " + fabric_mod_name + "_set_default_node_attrs,\n" - buf += " .get_task_tag = " + fabric_mod_name + "_get_task_tag,\n" buf += " .get_cmd_state = " + fabric_mod_name + "_get_cmd_state,\n" buf += " .queue_data_in = " + fabric_mod_name + "_queue_data_in,\n" buf += " .queue_status = " + fabric_mod_name + "_queue_status,\n" @@ -525,13 +524,6 @@ def tcm_mod_dump_fabric_ops(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += "}\n\n" bufi += "void " + fabric_mod_name + "_set_default_node_attrs(struct se_node_acl *);\n" - if re.search('get_task_tag\)\(', fo): - buf += "u32 " + fabric_mod_name + "_get_task_tag(struct se_cmd *se_cmd)\n" - buf += "{\n" - buf += " return 0;\n" - buf += "}\n\n" - bufi += "u32 " + fabric_mod_name + "_get_task_tag(struct se_cmd *);\n" - if re.search('get_cmd_state\)\(', fo): buf += "int " + fabric_mod_name + "_get_cmd_state(struct se_cmd *se_cmd)\n" buf += "{\n" diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 98e00360f97e..56df5cd918c5 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -1339,7 +1339,7 @@ static int srpt_abort_cmd(struct srpt_send_ioctx *ioctx) } pr_debug("Aborting cmd with state %d and tag %lld\n", state, - ioctx->tag); + ioctx->cmd.tag); switch (state) { case SRPT_STATE_NEW: @@ -1701,7 +1701,7 @@ static int srpt_handle_cmd(struct srpt_rdma_ch *ch, srp_cmd = recv_ioctx->ioctx.buf; cmd = &send_ioctx->cmd; - send_ioctx->tag = srp_cmd->tag; + cmd->tag = srp_cmd->tag; switch (srp_cmd->task_attr) { case SRP_CMD_SIMPLE_Q: @@ -1772,7 +1772,7 @@ static int srpt_rx_mgmt_fn_tag(struct srpt_send_ioctx *ioctx, u64 tag) for (i = 0; i < ch->rq_size; ++i) { target = ch->ioctx_ring[i]; if (target->cmd.se_lun == ioctx->cmd.se_lun && - target->tag == tag && + target->cmd.tag == tag && srpt_get_cmd_state(target) != SRPT_STATE_DONE) { ret = 0; /* now let the target core abort &target->cmd; */ @@ -1831,7 +1831,7 @@ static void srpt_handle_tsk_mgmt(struct srpt_rdma_ch *ch, srp_tsk->task_tag, srp_tsk->tag, ch->cm_id, ch->sess); srpt_set_cmd_state(send_ioctx, SRPT_STATE_MGMT); - send_ioctx->tag = srp_tsk->tag; + send_ioctx->cmd.tag = srp_tsk->tag; tcm_tmr = srp_tmr_to_tcm(srp_tsk->tsk_mgmt_func); if (tcm_tmr < 0) { send_ioctx->cmd.se_tmr_req->response = @@ -2979,7 +2979,7 @@ static int srpt_write_pending(struct se_cmd *se_cmd) case CH_DRAINING: case CH_RELEASING: pr_debug("cmd with tag %lld: channel disconnecting\n", - ioctx->tag); + ioctx->cmd.tag); srpt_set_cmd_state(ioctx, SRPT_STATE_DATA_IN); ret = -EINVAL; goto out; @@ -3054,24 +3054,24 @@ static void srpt_queue_response(struct se_cmd *cmd) ret = srpt_xfer_data(ch, ioctx); if (ret) { pr_err("xfer_data failed for tag %llu\n", - ioctx->tag); + ioctx->cmd.tag); return; } } if (state != SRPT_STATE_MGMT) - resp_len = srpt_build_cmd_rsp(ch, ioctx, ioctx->tag, + resp_len = srpt_build_cmd_rsp(ch, ioctx, ioctx->cmd.tag, cmd->scsi_status); else { srp_tm_status = tcm_to_srp_tsk_mgmt_status(cmd->se_tmr_req->response); resp_len = srpt_build_tskmgmt_rsp(ch, ioctx, srp_tm_status, - ioctx->tag); + ioctx->cmd.tag); } ret = srpt_post_send(ch, ioctx, resp_len); if (ret) { pr_err("sending cmd response failed for tag %llu\n", - ioctx->tag); + ioctx->cmd.tag); srpt_unmap_sg_to_ib_sge(ch, ioctx); srpt_set_cmd_state(ioctx, SRPT_STATE_DONE); target_put_sess_cmd(&ioctx->cmd); @@ -3479,14 +3479,6 @@ static void srpt_set_default_node_attrs(struct se_node_acl *nacl) { } -static u32 srpt_get_task_tag(struct se_cmd *se_cmd) -{ - struct srpt_send_ioctx *ioctx; - - ioctx = container_of(se_cmd, struct srpt_send_ioctx, cmd); - return ioctx->tag; -} - /* Note: only used from inside debug printk's by the TCM core. */ static int srpt_get_tcm_cmd_state(struct se_cmd *se_cmd) { @@ -3838,7 +3830,6 @@ static const struct target_core_fabric_ops srpt_template = { .write_pending = srpt_write_pending, .write_pending_status = srpt_write_pending_status, .set_default_node_attributes = srpt_set_default_node_attrs, - .get_task_tag = srpt_get_task_tag, .get_cmd_state = srpt_get_tcm_cmd_state, .queue_data_in = srpt_queue_data_in, .queue_status = srpt_queue_status, diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.h b/drivers/infiniband/ulp/srpt/ib_srpt.h index 33b2c88b73ba..6fec740742bd 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.h +++ b/drivers/infiniband/ulp/srpt/ib_srpt.h @@ -238,7 +238,6 @@ struct srpt_send_ioctx { bool rdma_aborted; struct se_cmd cmd; struct completion tx_done; - u64 tag; int sg_cnt; int mapped_sg_count; u16 n_rdma_ius; diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index fe8a8d157e22..e7515069e1ce 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -1191,7 +1191,7 @@ static int __qlt_24xx_handle_abts(struct scsi_qla_host *vha, list_for_each_entry(se_cmd, &se_sess->sess_cmd_list, se_cmd_list) { struct qla_tgt_cmd *cmd = container_of(se_cmd, struct qla_tgt_cmd, se_cmd); - if (cmd->tag == abts->exchange_addr_to_abort) { + if (se_cmd->tag == abts->exchange_addr_to_abort) { lun = cmd->unpacked_lun; found_lun = true; break; @@ -1728,9 +1728,8 @@ static int qlt_pre_xmit_response(struct qla_tgt_cmd *cmd, if (unlikely(cmd->aborted)) { ql_dbg(ql_dbg_tgt_mgt, vha, 0xf014, - "qla_target(%d): terminating exchange " - "for aborted cmd=%p (se_cmd=%p, tag=%d)", vha->vp_idx, cmd, - se_cmd, cmd->tag); + "qla_target(%d): terminating exchange for aborted cmd=%p (se_cmd=%p, tag=%lld)", + vha->vp_idx, cmd, se_cmd, se_cmd->tag); cmd->state = QLA_TGT_STATE_ABORTED; cmd->cmd_flags |= BIT_6; @@ -1765,18 +1764,17 @@ static int qlt_pre_xmit_response(struct qla_tgt_cmd *cmd, if (se_cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) { prm->residual = se_cmd->residual_count; ql_dbg(ql_dbg_io + ql_dbg_verbose, vha, 0x305c, - "Residual underflow: %d (tag %d, " - "op %x, bufflen %d, rq_result %x)\n", prm->residual, - cmd->tag, se_cmd->t_task_cdb ? se_cmd->t_task_cdb[0] : 0, - cmd->bufflen, prm->rq_result); + "Residual underflow: %d (tag %lld, op %x, bufflen %d, rq_result %x)\n", + prm->residual, se_cmd->tag, + se_cmd->t_task_cdb ? se_cmd->t_task_cdb[0] : 0, + cmd->bufflen, prm->rq_result); prm->rq_result |= SS_RESIDUAL_UNDER; } else if (se_cmd->se_cmd_flags & SCF_OVERFLOW_BIT) { prm->residual = se_cmd->residual_count; ql_dbg(ql_dbg_io, vha, 0x305d, - "Residual overflow: %d (tag %d, " - "op %x, bufflen %d, rq_result %x)\n", prm->residual, - cmd->tag, se_cmd->t_task_cdb ? se_cmd->t_task_cdb[0] : 0, - cmd->bufflen, prm->rq_result); + "Residual overflow: %d (tag %lld, op %x, bufflen %d, rq_result %x)\n", + prm->residual, se_cmd->tag, se_cmd->t_task_cdb ? + se_cmd->t_task_cdb[0] : 0, cmd->bufflen, prm->rq_result); prm->rq_result |= SS_RESIDUAL_OVER; } @@ -1849,7 +1847,7 @@ static void qlt_check_srr_debug(struct qla_tgt_cmd *cmd, int *xmit_type) == 50) { *xmit_type &= ~QLA_TGT_XMIT_STATUS; ql_dbg(ql_dbg_tgt_mgt, cmd->vha, 0xf015, - "Dropping cmd %p (tag %d) status", cmd, cmd->tag); + "Dropping cmd %p (tag %d) status", cmd, se_cmd->tag); } #endif /* @@ -1873,7 +1871,7 @@ static void qlt_check_srr_debug(struct qla_tgt_cmd *cmd, int *xmit_type) ql_dbg(ql_dbg_tgt_mgt, cmd->vha, 0xf016, "Cutting cmd %p (tag %d) buffer" " tail to len %d, sg_cnt %d (cmd->bufflen %d," - " cmd->sg_cnt %d)", cmd, cmd->tag, tot_len, leave, + " cmd->sg_cnt %d)", cmd, se_cmd->tag, tot_len, leave, cmd->bufflen, cmd->sg_cnt); cmd->bufflen = tot_len; @@ -1885,13 +1883,13 @@ static void qlt_check_srr_debug(struct qla_tgt_cmd *cmd, int *xmit_type) ql_dbg(ql_dbg_tgt_mgt, cmd->vha, 0xf017, "Cutting cmd %p (tag %d) buffer head " - "to offset %d (cmd->bufflen %d)", cmd, cmd->tag, offset, + "to offset %d (cmd->bufflen %d)", cmd, se_cmd->tag, offset, cmd->bufflen); if (offset == 0) *xmit_type &= ~QLA_TGT_XMIT_DATA; else if (qlt_set_data_offset(cmd, offset)) { ql_dbg(ql_dbg_tgt_mgt, cmd->vha, 0xf018, - "qlt_set_data_offset() failed (tag %d)", cmd->tag); + "qlt_set_data_offset() failed (tag %d)", se_cmd->tag); } } } @@ -3194,7 +3192,7 @@ skip_term: return; } else if (cmd->state == QLA_TGT_STATE_ABORTED) { ql_dbg(ql_dbg_tgt_mgt, vha, 0xf01e, - "Aborted command %p (tag %d) finished\n", cmd, cmd->tag); + "Aborted command %p (tag %lld) finished\n", cmd, se_cmd->tag); } else { ql_dbg(ql_dbg_tgt_mgt, vha, 0xf05c, "qla_target(%d): A command in state (%d) should " @@ -3266,7 +3264,7 @@ static void __qlt_do_work(struct qla_tgt_cmd *cmd) goto out_term; cdb = &atio->u.isp24.fcp_cmnd.cdb[0]; - cmd->tag = atio->u.isp24.exchange_addr; + cmd->se_cmd.tag = atio->u.isp24.exchange_addr; cmd->unpacked_lun = scsilun_to_int( (struct scsi_lun *)&atio->u.isp24.fcp_cmnd.lun); @@ -3891,9 +3889,8 @@ static void qlt_handle_srr(struct scsi_qla_host *vha, resp = 1; } else { ql_dbg(ql_dbg_tgt_mgt, vha, 0xf064, - "qla_target(%d): SRR for in data for cmd " - "without them (tag %d, SCSI status %d), " - "reject", vha->vp_idx, cmd->tag, + "qla_target(%d): SRR for in data for cmd without them (tag %lld, SCSI status %d), reject", + vha->vp_idx, se_cmd->tag, cmd->se_cmd.scsi_status); goto out_reject; } @@ -3927,10 +3924,8 @@ static void qlt_handle_srr(struct scsi_qla_host *vha, } } else { ql_dbg(ql_dbg_tgt_mgt, vha, 0xf066, - "qla_target(%d): SRR for out data for cmd " - "without them (tag %d, SCSI status %d), " - "reject", vha->vp_idx, cmd->tag, - cmd->se_cmd.scsi_status); + "qla_target(%d): SRR for out data for cmd without them (tag %lld, SCSI status %d), reject", + vha->vp_idx, se_cmd->tag, cmd->se_cmd.scsi_status); goto out_reject; } break; @@ -4051,10 +4046,9 @@ restart: cmd->sg = se_cmd->t_data_sg; ql_dbg(ql_dbg_tgt_mgt, vha, 0xf02c, - "SRR cmd %p (se_cmd %p, tag %d, op %x), " - "sg_cnt=%d, offset=%d", cmd, &cmd->se_cmd, cmd->tag, - se_cmd->t_task_cdb ? se_cmd->t_task_cdb[0] : 0, - cmd->sg_cnt, cmd->offset); + "SRR cmd %p (se_cmd %p, tag %lld, op %x), sg_cnt=%d, offset=%d", + cmd, &cmd->se_cmd, se_cmd->tag, se_cmd->t_task_cdb ? + se_cmd->t_task_cdb[0] : 0, cmd->sg_cnt, cmd->offset); qlt_handle_srr(vha, sctio, imm); diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h index 332086776dfe..985d76dd706b 100644 --- a/drivers/scsi/qla2xxx/qla_target.h +++ b/drivers/scsi/qla2xxx/qla_target.h @@ -924,7 +924,6 @@ struct qla_tgt_cmd { int sg_cnt; /* SG segments count */ int bufflen; /* cmd buffer length */ int offset; - uint32_t tag; uint32_t unpacked_lun; enum dma_data_direction dma_data_direction; uint32_t reset_count; diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index bd0f9eb67901..8e331220adda 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -421,19 +421,6 @@ static void tcm_qla2xxx_set_default_node_attrs(struct se_node_acl *nacl) return; } -static u32 tcm_qla2xxx_get_task_tag(struct se_cmd *se_cmd) -{ - struct qla_tgt_cmd *cmd; - - /* check for task mgmt cmd */ - if (se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB) - return 0xffffffff; - - cmd = container_of(se_cmd, struct qla_tgt_cmd, se_cmd); - - return cmd->tag; -} - static int tcm_qla2xxx_get_cmd_state(struct se_cmd *se_cmd) { return 0; @@ -1865,7 +1852,6 @@ static const struct target_core_fabric_ops tcm_qla2xxx_ops = { .write_pending = tcm_qla2xxx_write_pending, .write_pending_status = tcm_qla2xxx_write_pending_status, .set_default_node_attributes = tcm_qla2xxx_set_default_node_attrs, - .get_task_tag = tcm_qla2xxx_get_task_tag, .get_cmd_state = tcm_qla2xxx_get_cmd_state, .queue_data_in = tcm_qla2xxx_queue_data_in, .queue_status = tcm_qla2xxx_queue_status, @@ -1910,7 +1896,6 @@ static const struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = { .write_pending = tcm_qla2xxx_write_pending, .write_pending_status = tcm_qla2xxx_write_pending_status, .set_default_node_attributes = tcm_qla2xxx_set_default_node_attrs, - .get_task_tag = tcm_qla2xxx_get_task_tag, .get_cmd_state = tcm_qla2xxx_get_cmd_state, .queue_data_in = tcm_qla2xxx_queue_data_in, .queue_status = tcm_qla2xxx_queue_status, diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 866c167c0986..3c4431f71158 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -1008,6 +1008,8 @@ int iscsit_setup_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, if (cmd->sense_reason) goto attach_cmd; + /* only used for printks or comparing with ->ref_task_tag */ + cmd->se_cmd.tag = (__force u32)cmd->init_task_tag; cmd->sense_reason = target_setup_cmd_from_cdb(&cmd->se_cmd, hdr->cdb); if (cmd->sense_reason) { if (cmd->sense_reason == TCM_OUT_OF_RESOURCES) { diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index bd8af8764f4b..aa4fc4d8e176 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -1692,14 +1692,6 @@ static char *iscsi_get_fabric_name(void) return "iSCSI"; } -static u32 iscsi_get_task_tag(struct se_cmd *se_cmd) -{ - struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); - - /* only used for printks or comparism with ->ref_task_tag */ - return (__force u32)cmd->init_task_tag; -} - static int iscsi_get_cmd_state(struct se_cmd *se_cmd) { struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); @@ -1938,7 +1930,6 @@ const struct target_core_fabric_ops iscsi_ops = { .write_pending = lio_write_pending, .write_pending_status = lio_write_pending_status, .set_default_node_attributes = lio_set_default_node_attributes, - .get_task_tag = iscsi_get_task_tag, .get_cmd_state = iscsi_get_cmd_state, .queue_data_in = lio_queue_data_in, .queue_status = lio_queue_status, diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index b788406977f6..07d3b52c88eb 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -165,6 +165,7 @@ static void tcm_loop_submission_work(struct work_struct *work) transfer_length = scsi_bufflen(sc); } + se_cmd->tag = tl_cmd->sc_cmd_tag; rc = target_submit_cmd_map_sgls(se_cmd, tl_nexus->se_sess, sc->cmnd, &tl_cmd->tl_sense_buf[0], tl_cmd->sc->device->lun, transfer_length, TCM_SIMPLE_TAG, @@ -597,14 +598,6 @@ static void tcm_loop_set_default_node_attributes(struct se_node_acl *se_acl) return; } -static u32 tcm_loop_get_task_tag(struct se_cmd *se_cmd) -{ - struct tcm_loop_cmd *tl_cmd = container_of(se_cmd, - struct tcm_loop_cmd, tl_se_cmd); - - return tl_cmd->sc_cmd_tag; -} - static int tcm_loop_get_cmd_state(struct se_cmd *se_cmd) { struct tcm_loop_cmd *tl_cmd = container_of(se_cmd, @@ -1259,7 +1252,6 @@ static const struct target_core_fabric_ops loop_ops = { .write_pending = tcm_loop_write_pending, .write_pending_status = tcm_loop_write_pending_status, .set_default_node_attributes = tcm_loop_set_default_node_attributes, - .get_task_tag = tcm_loop_get_task_tag, .get_cmd_state = tcm_loop_get_cmd_state, .queue_data_in = tcm_loop_queue_data_in, .queue_status = tcm_loop_queue_status, diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index 89f172dc8678..2916a4023e71 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -1234,6 +1234,8 @@ static void sbp_handle_command(struct sbp_target_request *req) pr_debug("sbp_handle_command ORB:0x%llx unpacked_lun:%d data_len:%d data_dir:%d\n", req->orb_pointer, unpacked_lun, data_length, data_dir); + /* only used for printk until we do TMRs */ + req->se_cmd.tag = req->orb_pointer; if (target_submit_cmd(&req->se_cmd, sess->se_sess, req->cmd_buf, req->sense_buf, unpacked_lun, data_length, TCM_SIMPLE_TAG, data_dir, 0)) @@ -1768,15 +1770,6 @@ static void sbp_set_default_node_attrs(struct se_node_acl *nacl) return; } -static u32 sbp_get_task_tag(struct se_cmd *se_cmd) -{ - struct sbp_target_request *req = container_of(se_cmd, - struct sbp_target_request, se_cmd); - - /* only used for printk until we do TMRs */ - return (u32)req->orb_pointer; -} - static int sbp_get_cmd_state(struct se_cmd *se_cmd) { return 0; @@ -2377,7 +2370,6 @@ static const struct target_core_fabric_ops sbp_ops = { .write_pending = sbp_write_pending, .write_pending_status = sbp_write_pending_status, .set_default_node_attributes = sbp_set_default_node_attrs, - .get_task_tag = sbp_get_task_tag, .get_cmd_state = sbp_get_cmd_state, .queue_data_in = sbp_queue_data_in, .queue_status = sbp_queue_status, diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 5e2649fc6919..fc598c084523 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -374,10 +374,6 @@ static int target_fabric_tf_ops_check(const struct target_core_fabric_ops *tfo) pr_err("Missing tfo->set_default_node_attributes()\n"); return -EINVAL; } - if (!tfo->get_task_tag) { - pr_err("Missing tfo->get_task_tag()\n"); - return -EINVAL; - } if (!tfo->get_cmd_state) { pr_err("Missing tfo->get_cmd_state()\n"); return -EINVAL; diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c index b2e169fba3c6..393aca8bb3eb 100644 --- a/drivers/target/target_core_tmr.c +++ b/drivers/target/target_core_tmr.c @@ -117,7 +117,7 @@ void core_tmr_abort_task( { struct se_cmd *se_cmd; unsigned long flags; - int ref_tag; + u64 ref_tag; spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); list_for_each_entry(se_cmd, &se_sess->sess_cmd_list, se_cmd_list) { @@ -129,16 +129,17 @@ void core_tmr_abort_task( if (se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB) continue; - ref_tag = se_cmd->se_tfo->get_task_tag(se_cmd); + ref_tag = se_cmd->tag; if (tmr->ref_task_tag != ref_tag) continue; - printk("ABORT_TASK: Found referenced %s task_tag: %u\n", + printk("ABORT_TASK: Found referenced %s task_tag: %llu\n", se_cmd->se_tfo->get_fabric_name(), ref_tag); spin_lock(&se_cmd->t_state_lock); if (se_cmd->transport_state & CMD_T_COMPLETE) { - printk("ABORT_TASK: ref_tag: %u already complete, skipping\n", ref_tag); + printk("ABORT_TASK: ref_tag: %llu already complete," + " skipping\n", ref_tag); spin_unlock(&se_cmd->t_state_lock); spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); goto out; @@ -157,14 +158,14 @@ void core_tmr_abort_task( transport_cmd_finish_abort(se_cmd, true); printk("ABORT_TASK: Sending TMR_FUNCTION_COMPLETE for" - " ref_tag: %d\n", ref_tag); + " ref_tag: %llu\n", ref_tag); tmr->response = TMR_FUNCTION_COMPLETE; return; } spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); out: - printk("ABORT_TASK: Sending TMR_TASK_DOES_NOT_EXIST for ref_tag: %d\n", + printk("ABORT_TASK: Sending TMR_TASK_DOES_NOT_EXIST for ref_tag: %lld\n", tmr->ref_task_tag); tmr->response = TMR_TASK_DOES_NOT_EXIST; } @@ -289,16 +290,16 @@ static void core_tmr_drain_state_list( list_del(&cmd->state_list); pr_debug("LUN_RESET: %s cmd: %p" - " ITT/CmdSN: 0x%08x/0x%08x, i_state: %d, t_state: %d" + " ITT/CmdSN: 0x%08llx/0x%08x, i_state: %d, t_state: %d" "cdb: 0x%02x\n", (preempt_and_abort_list) ? "Preempt" : "", cmd, - cmd->se_tfo->get_task_tag(cmd), 0, + cmd->tag, 0, cmd->se_tfo->get_cmd_state(cmd), cmd->t_state, cmd->t_task_cdb[0]); - pr_debug("LUN_RESET: ITT[0x%08x] - pr_res_key: 0x%016Lx" + pr_debug("LUN_RESET: ITT[0x%08llx] - pr_res_key: 0x%016Lx" " -- CMD_T_ACTIVE: %d" " CMD_T_STOP: %d CMD_T_SENT: %d\n", - cmd->se_tfo->get_task_tag(cmd), cmd->pr_res_key, + cmd->tag, cmd->pr_res_key, (cmd->transport_state & CMD_T_ACTIVE) != 0, (cmd->transport_state & CMD_T_STOP) != 0, (cmd->transport_state & CMD_T_SENT) != 0); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 85b021e749e6..0d8662bb470e 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -600,9 +600,8 @@ static int transport_cmd_check_stop(struct se_cmd *cmd, bool remove_from_lists, * this command for frontend exceptions. */ if (cmd->transport_state & CMD_T_STOP) { - pr_debug("%s:%d CMD_T_STOP for ITT: 0x%08x\n", - __func__, __LINE__, - cmd->se_tfo->get_task_tag(cmd)); + pr_debug("%s:%d CMD_T_STOP for ITT: 0x%08llx\n", + __func__, __LINE__, cmd->tag); spin_unlock_irqrestore(&cmd->t_state_lock, flags); @@ -1155,6 +1154,8 @@ target_cmd_size_check(struct se_cmd *cmd, unsigned int size) /* * Used by fabric modules containing a local struct se_cmd within their * fabric dependent per I/O descriptor. + * + * Preserves the value of @cmd->tag. */ void transport_init_se_cmd( struct se_cmd *cmd, @@ -1380,6 +1381,8 @@ transport_generic_map_mem_to_cmd(struct se_cmd *cmd, struct scatterlist *sgl, * @sgl_prot: struct scatterlist memory protection information * @sgl_prot_count: scatterlist count for protection information * + * Task tags are supported if the caller has set @se_cmd->tag. + * * Returns non zero to signal active I/O shutdown failure. All other * setup exceptions will be returned as a SCSI CHECK_CONDITION response, * but still return zero here. @@ -1512,6 +1515,8 @@ EXPORT_SYMBOL(target_submit_cmd_map_sgls); * @data_dir: DMA data direction * @flags: flags for command submission from target_sc_flags_tables * + * Task tags are supported if the caller has set @se_cmd->tag. + * * Returns non zero to signal active I/O shutdown failure. All other * setup exceptions will be returned as a SCSI CHECK_CONDITION response, * but still return zero here. @@ -1639,9 +1644,8 @@ void transport_generic_request_failure(struct se_cmd *cmd, { int ret = 0; - pr_debug("-----[ Storage Engine Exception for cmd: %p ITT: 0x%08x" - " CDB: 0x%02x\n", cmd, cmd->se_tfo->get_task_tag(cmd), - cmd->t_task_cdb[0]); + pr_debug("-----[ Storage Engine Exception for cmd: %p ITT: 0x%08llx" + " CDB: 0x%02x\n", cmd, cmd->tag, cmd->t_task_cdb[0]); pr_debug("-----[ i_state: %d t_state: %d sense_reason: %d\n", cmd->se_tfo->get_cmd_state(cmd), cmd->t_state, sense_reason); @@ -1849,9 +1853,8 @@ void target_execute_cmd(struct se_cmd *cmd) */ spin_lock_irq(&cmd->t_state_lock); if (cmd->transport_state & CMD_T_STOP) { - pr_debug("%s:%d CMD_T_STOP for ITT: 0x%08x\n", - __func__, __LINE__, - cmd->se_tfo->get_task_tag(cmd)); + pr_debug("%s:%d CMD_T_STOP for ITT: 0x%08llx\n", + __func__, __LINE__, cmd->tag); spin_unlock_irq(&cmd->t_state_lock); complete_all(&cmd->t_transport_stop_comp); @@ -2658,10 +2661,8 @@ bool transport_wait_for_tasks(struct se_cmd *cmd) cmd->transport_state |= CMD_T_STOP; - pr_debug("wait_for_tasks: Stopping %p ITT: 0x%08x" - " i_state: %d, t_state: %d, CMD_T_STOP\n", - cmd, cmd->se_tfo->get_task_tag(cmd), - cmd->se_tfo->get_cmd_state(cmd), cmd->t_state); + pr_debug("wait_for_tasks: Stopping %p ITT: 0x%08llx i_state: %d, t_state: %d, CMD_T_STOP\n", + cmd, cmd->tag, cmd->se_tfo->get_cmd_state(cmd), cmd->t_state); spin_unlock_irqrestore(&cmd->t_state_lock, flags); @@ -2670,9 +2671,8 @@ bool transport_wait_for_tasks(struct se_cmd *cmd) spin_lock_irqsave(&cmd->t_state_lock, flags); cmd->transport_state &= ~(CMD_T_ACTIVE | CMD_T_STOP); - pr_debug("wait_for_tasks: Stopped wait_for_completion(" - "&cmd->t_transport_stop_comp) for ITT: 0x%08x\n", - cmd->se_tfo->get_task_tag(cmd)); + pr_debug("wait_for_tasks: Stopped wait_for_completion(&cmd->t_transport_stop_comp) for ITT: 0x%08llx\n", + cmd->tag); spin_unlock_irqrestore(&cmd->t_state_lock, flags); @@ -2974,8 +2974,8 @@ int transport_check_aborted_status(struct se_cmd *cmd, int send_status) if (!send_status || !(cmd->se_cmd_flags & SCF_SEND_DELAYED_TAS)) return 1; - pr_debug("Sending delayed SAM_STAT_TASK_ABORTED status for CDB: 0x%02x ITT: 0x%08x\n", - cmd->t_task_cdb[0], cmd->se_tfo->get_task_tag(cmd)); + pr_debug("Sending delayed SAM_STAT_TASK_ABORTED status for CDB: 0x%02x ITT: 0x%08llx\n", + cmd->t_task_cdb[0], cmd->tag); cmd->se_cmd_flags &= ~SCF_SEND_DELAYED_TAS; cmd->scsi_status = SAM_STAT_TASK_ABORTED; @@ -3014,9 +3014,8 @@ void transport_send_task_abort(struct se_cmd *cmd) transport_lun_remove_cmd(cmd); - pr_debug("Setting SAM_STAT_TASK_ABORTED status for CDB: 0x%02x," - " ITT: 0x%08x\n", cmd->t_task_cdb[0], - cmd->se_tfo->get_task_tag(cmd)); + pr_debug("Setting SAM_STAT_TASK_ABORTED status for CDB: 0x%02x, ITT: 0x%08llx\n", + cmd->t_task_cdb[0], cmd->tag); trace_target_cmd_complete(cmd); cmd->se_tfo->queue_status(cmd); diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c index 8fd680ac941b..5545619d3045 100644 --- a/drivers/target/target_core_xcopy.c +++ b/drivers/target/target_core_xcopy.c @@ -359,11 +359,6 @@ static char *xcopy_pt_get_fabric_name(void) return "xcopy-pt"; } -static u32 xcopy_pt_get_tag(struct se_cmd *se_cmd) -{ - return 0; -} - static int xcopy_pt_get_cmd_state(struct se_cmd *se_cmd) { return 0; @@ -424,7 +419,6 @@ static int xcopy_pt_queue_status(struct se_cmd *se_cmd) static const struct target_core_fabric_ops xcopy_pt_tfo = { .get_fabric_name = xcopy_pt_get_fabric_name, - .get_task_tag = xcopy_pt_get_tag, .get_cmd_state = xcopy_pt_get_cmd_state, .release_cmd = xcopy_pt_release_cmd, .check_stop_free = xcopy_pt_check_stop_free, @@ -575,6 +569,7 @@ static int target_xcopy_setup_pt_cmd( xpt_cmd->xcopy_op = xop; target_xcopy_setup_pt_port(xpt_cmd, xop, remote_port); + cmd->tag = 0; sense_rc = target_setup_cmd_from_cdb(cmd, cdb); if (sense_rc) { ret = -EINVAL; diff --git a/drivers/target/tcm_fc/tcm_fc.h b/drivers/target/tcm_fc/tcm_fc.h index 4ceaeb9a4b93..39909dadef3e 100644 --- a/drivers/target/tcm_fc/tcm_fc.h +++ b/drivers/target/tcm_fc/tcm_fc.h @@ -157,7 +157,6 @@ int ft_queue_status(struct se_cmd *); int ft_queue_data_in(struct se_cmd *); int ft_write_pending(struct se_cmd *); int ft_write_pending_status(struct se_cmd *); -u32 ft_get_task_tag(struct se_cmd *); int ft_get_cmd_state(struct se_cmd *); void ft_queue_tm_resp(struct se_cmd *); void ft_aborted_task(struct se_cmd *); diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c index edcafa4490c0..a8fe6ed5262f 100644 --- a/drivers/target/tcm_fc/tfc_cmd.c +++ b/drivers/target/tcm_fc/tfc_cmd.c @@ -247,15 +247,6 @@ int ft_write_pending(struct se_cmd *se_cmd) return 0; } -u32 ft_get_task_tag(struct se_cmd *se_cmd) -{ - struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd); - - if (cmd->aborted) - return ~0; - return fc_seq_exch(cmd->seq)->rxid; -} - int ft_get_cmd_state(struct se_cmd *se_cmd) { return 0; @@ -568,6 +559,7 @@ static void ft_send_work(struct work_struct *work) } fc_seq_exch(cmd->seq)->lp->tt.seq_set_resp(cmd->seq, ft_recv_seq, cmd); + cmd->se_cmd.tag = fc_seq_exch(cmd->seq)->rxid; /* * Use a single se_cmd->cmd_kref as we expect to release se_cmd * directly from ft_check_stop_free callback in response path. diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c index 6ad7404b7dd1..f0821967f0a1 100644 --- a/drivers/target/tcm_fc/tfc_conf.c +++ b/drivers/target/tcm_fc/tfc_conf.c @@ -468,7 +468,6 @@ static const struct target_core_fabric_ops ft_fabric_ops = { .write_pending = ft_write_pending, .write_pending_status = ft_write_pending_status, .set_default_node_attributes = ft_set_default_node_attr, - .get_task_tag = ft_get_task_tag, .get_cmd_state = ft_get_cmd_state, .queue_data_in = ft_queue_data_in, .queue_status = ft_queue_status, diff --git a/drivers/usb/gadget/legacy/tcm_usb_gadget.c b/drivers/usb/gadget/legacy/tcm_usb_gadget.c index 77cdbb56e1d5..a000d89dc78a 100644 --- a/drivers/usb/gadget/legacy/tcm_usb_gadget.c +++ b/drivers/usb/gadget/legacy/tcm_usb_gadget.c @@ -1112,6 +1112,7 @@ static int usbg_submit_command(struct f_uas *fu, memcpy(cmd->cmd_buf, cmd_iu->cdb, cmd_len); cmd->tag = be16_to_cpup(&cmd_iu->tag); + cmd->se_cmd.tag = cmd->tag; if (fu->flags & USBG_USE_STREAMS) { if (cmd->tag > UASP_SS_EP_COMP_NUM_STREAMS) goto err; @@ -1245,6 +1246,7 @@ static int bot_submit_command(struct f_uas *fu, cmd->unpacked_lun = cbw->Lun; cmd->is_read = cbw->Flags & US_BULK_FLAG_IN ? 1 : 0; cmd->data_len = le32_to_cpu(cbw->DataTransferLength); + cmd->se_cmd.tag = le32_to_cpu(cmd->bot_tag); INIT_WORK(&cmd->work, bot_cmd_work); ret = queue_work(tpg->workqueue, &cmd->work); @@ -1340,18 +1342,6 @@ static void usbg_set_default_node_attrs(struct se_node_acl *nacl) return; } -static u32 usbg_get_task_tag(struct se_cmd *se_cmd) -{ - struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd, - se_cmd); - struct f_uas *fu = cmd->fu; - - if (fu->flags & USBG_IS_BOT) - return le32_to_cpu(cmd->bot_tag); - else - return cmd->tag; -} - static int usbg_get_cmd_state(struct se_cmd *se_cmd) { return 0; @@ -1739,7 +1729,6 @@ static const struct target_core_fabric_ops usbg_ops = { .write_pending = usbg_send_write_request, .write_pending_status = usbg_write_pending_status, .set_default_node_attributes = usbg_set_default_node_attrs, - .get_task_tag = usbg_get_task_tag, .get_cmd_state = usbg_get_cmd_state, .queue_data_in = usbg_send_read_response, .queue_status = usbg_send_status_response, diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index db9f4b474214..4a003948b07f 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -369,11 +369,6 @@ static void vhost_scsi_set_default_node_attrs(struct se_node_acl *nacl) return; } -static u32 vhost_scsi_get_task_tag(struct se_cmd *se_cmd) -{ - return 0; -} - static int vhost_scsi_get_cmd_state(struct se_cmd *se_cmd) { return 0; @@ -818,6 +813,7 @@ static void vhost_scsi_submission_work(struct work_struct *work) } tv_nexus = cmd->tvc_nexus; + se_cmd->tag = 0; rc = target_submit_cmd_map_sgls(se_cmd, tv_nexus->tvn_se_sess, cmd->tvc_cdb, &cmd->tvc_sense_buf[0], cmd->tvc_lun, cmd->tvc_exp_data_len, @@ -2148,7 +2144,6 @@ static struct target_core_fabric_ops vhost_scsi_ops = { .write_pending = vhost_scsi_write_pending, .write_pending_status = vhost_scsi_write_pending_status, .set_default_node_attributes = vhost_scsi_set_default_node_attrs, - .get_task_tag = vhost_scsi_get_task_tag, .get_cmd_state = vhost_scsi_get_cmd_state, .queue_data_in = vhost_scsi_queue_data_in, .queue_status = vhost_scsi_queue_status, diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index 10c71a5616fa..ea929baf7ad0 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -400,6 +400,7 @@ static void scsiback_cmd_exec(struct vscsibk_pend *pending_req) memset(se_cmd, 0, sizeof(*se_cmd)); scsiback_get(pending_req->info); + se_cmd->tag = pending_req->rqid; rc = target_submit_cmd_map_sgls(se_cmd, sess, pending_req->cmnd, pending_req->sense_buffer, pending_req->v2p->lun, pending_req->data_len, 0, @@ -1394,14 +1395,6 @@ static void scsiback_set_default_node_attrs(struct se_node_acl *nacl) { } -static u32 scsiback_get_task_tag(struct se_cmd *se_cmd) -{ - struct vscsibk_pend *pending_req = container_of(se_cmd, - struct vscsibk_pend, se_cmd); - - return pending_req->rqid; -} - static int scsiback_get_cmd_state(struct se_cmd *se_cmd) { return 0; @@ -1833,7 +1826,6 @@ static const struct target_core_fabric_ops scsiback_ops = { .write_pending = scsiback_write_pending, .write_pending_status = scsiback_write_pending_status, .set_default_node_attributes = scsiback_set_default_node_attrs, - .get_task_tag = scsiback_get_task_tag, .get_cmd_state = scsiback_get_cmd_state, .queue_data_in = scsiback_queue_data_in, .queue_status = scsiback_queue_status, diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index c462fb0a47f4..042a73464966 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -420,7 +420,7 @@ struct se_tmr_req { u8 response; int call_transport; /* Reference to ITT that Task Mgmt should be performed */ - u32 ref_task_tag; + u64 ref_task_tag; void *fabric_tmr_ptr; struct se_cmd *task_cmd; struct se_device *tmr_dev; @@ -473,6 +473,7 @@ struct se_cmd { u8 scsi_asc; u8 scsi_ascq; u16 scsi_sense_length; + u64 tag; /* SAM command identifier aka task tag */ /* Delay for ALUA Active/NonOptimized state access in milliseconds */ int alua_nonop_delay; /* See include/linux/dma-mapping.h */ diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index a420f434c6c5..f64d493f888b 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -53,7 +53,6 @@ struct target_core_fabric_ops { int (*write_pending)(struct se_cmd *); int (*write_pending_status)(struct se_cmd *); void (*set_default_node_attributes)(struct se_node_acl *); - u32 (*get_task_tag)(struct se_cmd *); int (*get_cmd_state)(struct se_cmd *); int (*queue_data_in)(struct se_cmd *); int (*queue_status)(struct se_cmd *); -- cgit v1.2.3-70-g09d2 From 2fe6e721b575e308d16e37a0beff107cafd5cf9b Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 14 Apr 2015 13:15:29 +0200 Subject: ib_srpt: Remove set-but-not-used variables Detected these variables by building with W=1. Signed-off-by: Bart Van Assche Signed-off-by: Nicholas Bellinger --- drivers/infiniband/ulp/srpt/ib_srpt.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 56df5cd918c5..f21a5f6bf858 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -1387,7 +1387,6 @@ static void srpt_handle_send_err_comp(struct srpt_rdma_ch *ch, u64 wr_id) { struct srpt_send_ioctx *ioctx; enum srpt_command_state state; - struct se_cmd *cmd; u32 index; atomic_inc(&ch->sq_wr_avail); @@ -1395,7 +1394,6 @@ static void srpt_handle_send_err_comp(struct srpt_rdma_ch *ch, u64 wr_id) index = idx_from_wr_id(wr_id); ioctx = ch->ioctx_ring[index]; state = srpt_get_cmd_state(ioctx); - cmd = &ioctx->cmd; WARN_ON(state != SRPT_STATE_CMD_RSP_SENT && state != SRPT_STATE_MGMT_RSP_SENT @@ -1472,10 +1470,8 @@ static void srpt_handle_rdma_err_comp(struct srpt_rdma_ch *ch, struct srpt_send_ioctx *ioctx, enum srpt_opcode opcode) { - struct se_cmd *cmd; enum srpt_command_state state; - cmd = &ioctx->cmd; state = srpt_get_cmd_state(ioctx); switch (opcode) { case SRPT_RDMA_READ_LAST: @@ -2176,12 +2172,9 @@ static void srpt_destroy_ch_ib(struct srpt_rdma_ch *ch) */ static void __srpt_close_ch(struct srpt_rdma_ch *ch) { - struct srpt_device *sdev; enum rdma_ch_state prev_state; unsigned long flags; - sdev = ch->sport->sdev; - spin_lock_irqsave(&ch->spinlock, flags); prev_state = ch->state; switch (prev_state) { -- cgit v1.2.3-70-g09d2 From 45fb94c2925fc7d9b170f2d148f91556428eaa1d Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 14 Apr 2015 13:00:58 +0200 Subject: target: Remove set-but-not-used-variables Detected these variables by building with W=1. Signed-off-by: Bart Van Assche Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_configfs.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index fc598c084523..86caeb26f996 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -1006,8 +1006,8 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( u64 sa_res_key = 0; u32 mapped_lun = 0, target_lun = 0; int ret = -1, res_holder = 0, all_tg_pt = 0, arg, token; - u16 port_rpti = 0, tpgt = 0; - u8 type = 0, scope; + u16 tpgt = 0; + u8 type = 0; if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH) return 0; @@ -1087,7 +1087,6 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( break; case Opt_res_scope: match_int(args, &arg); - scope = (u8)arg; break; case Opt_res_all_tg_pt: match_int(args, &arg); @@ -1127,7 +1126,6 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( break; case Opt_port_rtpi: match_int(args, &arg); - port_rpti = (u16)arg; break; case Opt_target_lun: match_int(args, &arg); -- cgit v1.2.3-70-g09d2 From ef0caf8dd149992796ee453b65dd0d77ff848f57 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 3 May 2015 08:50:53 +0200 Subject: target: don't copy fabric ops Now that we don't need to set up ->tf_subsys we don't need to copy around the ops vector anymore. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_configfs.c | 2 +- drivers/target/target_core_fabric_configfs.c | 38 ++++++++++++++-------------- include/target/target_core_configfs.h | 2 +- 3 files changed, 21 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 86caeb26f996..43c9ed1d1b92 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -444,7 +444,7 @@ int target_register_template(const struct target_core_fabric_ops *fo) tf->tf_module = fo->module; snprintf(tf->tf_name, TARGET_FABRIC_NAME_SIZE, "%s", fo->name); - tf->tf_ops = *fo; + tf->tf_ops = fo; target_fabric_setup_cits(tf); mutex_lock(&g_tf_lock); diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index f4d9467c3e14..93564c0b7576 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -61,7 +61,7 @@ static void target_fabric_setup_##_name##_cit(struct target_fabric_configfs *tf) { \ struct target_fabric_configfs_template *tfc = &tf->tf_cit_tmpl; \ struct config_item_type *cit = &tfc->tfc_##_name##_cit; \ - struct configfs_attribute **attrs = tf->tf_ops.tfc_##_name##_attrs; \ + struct configfs_attribute **attrs = tf->tf_ops->tfc_##_name##_attrs; \ \ cit->ct_item_ops = _item_ops; \ cit->ct_group_ops = _group_ops; \ @@ -460,8 +460,8 @@ static void target_fabric_nacl_base_release(struct config_item *item) struct se_node_acl, acl_group); struct target_fabric_configfs *tf = se_nacl->se_tpg->se_tpg_wwn->wwn_tf; - if (tf->tf_ops.fabric_cleanup_nodeacl) - tf->tf_ops.fabric_cleanup_nodeacl(se_nacl); + if (tf->tf_ops->fabric_cleanup_nodeacl) + tf->tf_ops->fabric_cleanup_nodeacl(se_nacl); core_tpg_del_initiator_node_acl(se_nacl); } @@ -506,8 +506,8 @@ static struct config_group *target_fabric_make_nodeacl( if (IS_ERR(se_nacl)) return ERR_CAST(se_nacl); - if (tf->tf_ops.fabric_init_nodeacl) { - int ret = tf->tf_ops.fabric_init_nodeacl(se_nacl, name); + if (tf->tf_ops->fabric_init_nodeacl) { + int ret = tf->tf_ops->fabric_init_nodeacl(se_nacl, name); if (ret) { core_tpg_del_initiator_node_acl(se_nacl); return ERR_PTR(ret); @@ -579,7 +579,7 @@ static void target_fabric_np_base_release(struct config_item *item) struct se_portal_group *se_tpg = se_tpg_np->tpg_np_parent; struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; - tf->tf_ops.fabric_drop_np(se_tpg_np); + tf->tf_ops->fabric_drop_np(se_tpg_np); } static struct configfs_item_operations target_fabric_np_base_item_ops = { @@ -603,12 +603,12 @@ static struct config_group *target_fabric_make_np( struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; struct se_tpg_np *se_tpg_np; - if (!tf->tf_ops.fabric_make_np) { + if (!tf->tf_ops->fabric_make_np) { pr_err("tf->tf_ops.fabric_make_np is NULL\n"); return ERR_PTR(-ENOSYS); } - se_tpg_np = tf->tf_ops.fabric_make_np(se_tpg, group, name); + se_tpg_np = tf->tf_ops->fabric_make_np(se_tpg, group, name); if (!se_tpg_np || IS_ERR(se_tpg_np)) return ERR_PTR(-EINVAL); @@ -808,13 +808,13 @@ static int target_fabric_port_link( goto out; } - if (tf->tf_ops.fabric_post_link) { + if (tf->tf_ops->fabric_post_link) { /* * Call the optional fabric_post_link() to allow a * fabric module to setup any additional state once * core_dev_add_lun() has been called.. */ - tf->tf_ops.fabric_post_link(se_tpg, lun); + tf->tf_ops->fabric_post_link(se_tpg, lun); } return 0; @@ -831,13 +831,13 @@ static int target_fabric_port_unlink( struct se_portal_group *se_tpg = lun->lun_sep->sep_tpg; struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; - if (tf->tf_ops.fabric_pre_unlink) { + if (tf->tf_ops->fabric_pre_unlink) { /* * Call the optional fabric_pre_unlink() to allow a * fabric module to release any additional stat before * core_dev_del_lun() is called. */ - tf->tf_ops.fabric_pre_unlink(se_tpg, lun); + tf->tf_ops->fabric_pre_unlink(se_tpg, lun); } core_dev_del_lun(se_tpg, lun); @@ -1027,7 +1027,7 @@ static void target_fabric_tpg_release(struct config_item *item) struct se_wwn *wwn = se_tpg->se_tpg_wwn; struct target_fabric_configfs *tf = wwn->wwn_tf; - tf->tf_ops.fabric_drop_tpg(se_tpg); + tf->tf_ops->fabric_drop_tpg(se_tpg); } static struct configfs_item_operations target_fabric_tpg_base_item_ops = { @@ -1050,12 +1050,12 @@ static struct config_group *target_fabric_make_tpg( struct target_fabric_configfs *tf = wwn->wwn_tf; struct se_portal_group *se_tpg; - if (!tf->tf_ops.fabric_make_tpg) { - pr_err("tf->tf_ops.fabric_make_tpg is NULL\n"); + if (!tf->tf_ops->fabric_make_tpg) { + pr_err("tf->tf_ops->fabric_make_tpg is NULL\n"); return ERR_PTR(-ENOSYS); } - se_tpg = tf->tf_ops.fabric_make_tpg(wwn, group, name); + se_tpg = tf->tf_ops->fabric_make_tpg(wwn, group, name); if (!se_tpg || IS_ERR(se_tpg)) return ERR_PTR(-EINVAL); /* @@ -1116,7 +1116,7 @@ static void target_fabric_release_wwn(struct config_item *item) struct se_wwn, wwn_group); struct target_fabric_configfs *tf = wwn->wwn_tf; - tf->tf_ops.fabric_drop_wwn(wwn); + tf->tf_ops->fabric_drop_wwn(wwn); } static struct configfs_item_operations target_fabric_tpg_item_ops = { @@ -1152,12 +1152,12 @@ static struct config_group *target_fabric_make_wwn( struct target_fabric_configfs, tf_group); struct se_wwn *wwn; - if (!tf->tf_ops.fabric_make_wwn) { + if (!tf->tf_ops->fabric_make_wwn) { pr_err("tf->tf_ops.fabric_make_wwn is NULL\n"); return ERR_PTR(-ENOSYS); } - wwn = tf->tf_ops.fabric_make_wwn(tf, group, name); + wwn = tf->tf_ops->fabric_make_wwn(tf, group, name); if (!wwn || IS_ERR(wwn)) return ERR_PTR(-EINVAL); diff --git a/include/target/target_core_configfs.h b/include/target/target_core_configfs.h index b99c01170392..10402e5526e7 100644 --- a/include/target/target_core_configfs.h +++ b/include/target/target_core_configfs.h @@ -42,7 +42,7 @@ struct target_fabric_configfs { struct config_item_type *tf_fabric_cit; /* Pointer to fabric's struct module */ struct module *tf_module; - struct target_core_fabric_ops tf_ops; + const struct target_core_fabric_ops *tf_ops; struct target_fabric_configfs_template tf_cit_tmpl; }; -- cgit v1.2.3-70-g09d2 From 0dc2e8d1435318dc448ac390d6d31e6cd2516684 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 3 May 2015 08:50:54 +0200 Subject: target: put struct target_fabric_configfs on a diet Remove all fields that are either unused or can be replaced by trivially following pointers. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_configfs.c | 24 ++++-------------------- drivers/target/target_core_fabric_configfs.c | 4 ++-- include/target/target_core_configfs.h | 7 ------- 3 files changed, 6 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 43c9ed1d1b92..f63e4dda8a90 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -116,7 +116,7 @@ static struct target_fabric_configfs *target_core_get_fabric( mutex_lock(&g_tf_lock); list_for_each_entry(tf, &g_tf_list, tf_list) { - if (!strcmp(tf->tf_name, name)) { + if (!strcmp(tf->tf_ops->name, name)) { atomic_inc(&tf->tf_access_cnt); mutex_unlock(&g_tf_lock); return tf; @@ -193,7 +193,7 @@ static struct config_group *target_core_register_fabric( return ERR_PTR(-EINVAL); } pr_debug("Target_Core_ConfigFS: REGISTER -> Located fabric:" - " %s\n", tf->tf_name); + " %s\n", tf->tf_ops->name); /* * On a successful target_core_get_fabric() look, the returned * struct target_fabric_configfs *tf will contain a usage reference. @@ -212,10 +212,6 @@ static struct config_group *target_core_register_fabric( pr_debug("Target_Core_ConfigFS: REGISTER -> Allocated Fabric:" " %s\n", tf->tf_group.cg_item.ci_name); - tf->tf_fabric = &tf->tf_group.cg_item; - pr_debug("Target_Core_ConfigFS: REGISTER -> Set tf->tf_fabric" - " for %s\n", name); - return &tf->tf_group; } @@ -236,13 +232,9 @@ static void target_core_deregister_fabric( " tf list\n", config_item_name(item)); pr_debug("Target_Core_ConfigFS: DEREGISTER -> located fabric:" - " %s\n", tf->tf_name); + " %s\n", tf->tf_ops->name); atomic_dec(&tf->tf_access_cnt); - pr_debug("Target_Core_ConfigFS: DEREGISTER -> Releasing" - " tf->tf_fabric for %s\n", tf->tf_name); - tf->tf_fabric = NULL; - pr_debug("Target_Core_ConfigFS: DEREGISTER -> Releasing ci" " %s\n", config_item_name(item)); @@ -436,14 +428,6 @@ int target_register_template(const struct target_core_fabric_ops *fo) INIT_LIST_HEAD(&tf->tf_list); atomic_set(&tf->tf_access_cnt, 0); - - /* - * Setup the default generic struct config_item_type's (cits) in - * struct target_fabric_configfs->tf_cit_tmpl - */ - tf->tf_module = fo->module; - snprintf(tf->tf_name, TARGET_FABRIC_NAME_SIZE, "%s", fo->name); - tf->tf_ops = fo; target_fabric_setup_cits(tf); @@ -461,7 +445,7 @@ void target_unregister_template(const struct target_core_fabric_ops *fo) mutex_lock(&g_tf_lock); list_for_each_entry(t, &g_tf_list, tf_list) { - if (!strcmp(t->tf_name, fo->name)) { + if (!strcmp(t->tf_ops->name, fo->name)) { BUG_ON(atomic_read(&t->tf_access_cnt)); list_del(&t->tf_list); kfree(t); diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index 93564c0b7576..d2ce61a07afd 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -52,7 +52,7 @@ static void target_fabric_setup_##_name##_cit(struct target_fabric_configfs *tf) cit->ct_item_ops = _item_ops; \ cit->ct_group_ops = _group_ops; \ cit->ct_attrs = _attrs; \ - cit->ct_owner = tf->tf_module; \ + cit->ct_owner = tf->tf_ops->module; \ pr_debug("Setup generic %s\n", __stringify(_name)); \ } @@ -66,7 +66,7 @@ static void target_fabric_setup_##_name##_cit(struct target_fabric_configfs *tf) cit->ct_item_ops = _item_ops; \ cit->ct_group_ops = _group_ops; \ cit->ct_attrs = attrs; \ - cit->ct_owner = tf->tf_module; \ + cit->ct_owner = tf->tf_ops->module; \ pr_debug("Setup generic %s\n", __stringify(_name)); \ } diff --git a/include/target/target_core_configfs.h b/include/target/target_core_configfs.h index 10402e5526e7..3f11d2ead63d 100644 --- a/include/target/target_core_configfs.h +++ b/include/target/target_core_configfs.h @@ -30,18 +30,11 @@ struct target_fabric_configfs_template { }; struct target_fabric_configfs { - char tf_name[TARGET_FABRIC_NAME_SIZE]; atomic_t tf_access_cnt; struct list_head tf_list; struct config_group tf_group; struct config_group tf_disc_group; struct config_group *tf_default_groups[2]; - /* Pointer to fabric's config_item */ - struct config_item *tf_fabric; - /* Passed from fabric modules */ - struct config_item_type *tf_fabric_cit; - /* Pointer to fabric's struct module */ - struct module *tf_module; const struct target_core_fabric_ops *tf_ops; struct target_fabric_configfs_template tf_cit_tmpl; }; -- cgit v1.2.3-70-g09d2 From 968ebe752035d14a4c2bb69f8ed0ddf7292dd2f9 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 3 May 2015 08:50:55 +0200 Subject: target: remove struct target_fabric_configfs_template It's only embedded into struct target_fabric_configfs these days, so we might as well remove this layer of abstraction. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_configfs.c | 7 ++-- drivers/target/target_core_fabric_configfs.c | 46 ++++++++++++-------------- include/target/target_core_configfs.h | 48 +++++++++++++--------------- 3 files changed, 46 insertions(+), 55 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index f63e4dda8a90..798386a1b6e7 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -199,16 +199,15 @@ static struct config_group *target_core_register_fabric( * struct target_fabric_configfs *tf will contain a usage reference. */ pr_debug("Target_Core_ConfigFS: REGISTER tfc_wwn_cit -> %p\n", - &tf->tf_cit_tmpl.tfc_wwn_cit); + &tf->tf_wwn_cit); tf->tf_group.default_groups = tf->tf_default_groups; tf->tf_group.default_groups[0] = &tf->tf_disc_group; tf->tf_group.default_groups[1] = NULL; - config_group_init_type_name(&tf->tf_group, name, - &tf->tf_cit_tmpl.tfc_wwn_cit); + config_group_init_type_name(&tf->tf_group, name, &tf->tf_wwn_cit); config_group_init_type_name(&tf->tf_disc_group, "discovery_auth", - &tf->tf_cit_tmpl.tfc_discovery_cit); + &tf->tf_discovery_cit); pr_debug("Target_Core_ConfigFS: REGISTER -> Allocated Fabric:" " %s\n", tf->tf_group.cg_item.ci_name); diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index d2ce61a07afd..6cb4828308e9 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -46,8 +46,7 @@ #define TF_CIT_SETUP(_name, _item_ops, _group_ops, _attrs) \ static void target_fabric_setup_##_name##_cit(struct target_fabric_configfs *tf) \ { \ - struct target_fabric_configfs_template *tfc = &tf->tf_cit_tmpl; \ - struct config_item_type *cit = &tfc->tfc_##_name##_cit; \ + struct config_item_type *cit = &tf->tf_##_name##_cit; \ \ cit->ct_item_ops = _item_ops; \ cit->ct_group_ops = _group_ops; \ @@ -59,8 +58,7 @@ static void target_fabric_setup_##_name##_cit(struct target_fabric_configfs *tf) #define TF_CIT_SETUP_DRV(_name, _item_ops, _group_ops) \ static void target_fabric_setup_##_name##_cit(struct target_fabric_configfs *tf) \ { \ - struct target_fabric_configfs_template *tfc = &tf->tf_cit_tmpl; \ - struct config_item_type *cit = &tfc->tfc_##_name##_cit; \ + struct config_item_type *cit = &tf->tf_##_name##_cit; \ struct configfs_attribute **attrs = tf->tf_ops->tfc_##_name##_attrs; \ \ cit->ct_item_ops = _item_ops; \ @@ -399,9 +397,9 @@ static struct config_group *target_fabric_make_mappedlun( } config_group_init_type_name(&lacl->se_lun_group, name, - &tf->tf_cit_tmpl.tfc_tpg_mappedlun_cit); + &tf->tf_tpg_mappedlun_cit); config_group_init_type_name(&lacl->ml_stat_grps.stat_group, - "statistics", &tf->tf_cit_tmpl.tfc_tpg_mappedlun_stat_cit); + "statistics", &tf->tf_tpg_mappedlun_stat_cit); lacl_cg->default_groups[0] = &lacl->ml_stat_grps.stat_group; lacl_cg->default_groups[1] = NULL; @@ -523,16 +521,15 @@ static struct config_group *target_fabric_make_nodeacl( nacl_cg->default_groups[4] = NULL; config_group_init_type_name(&se_nacl->acl_group, name, - &tf->tf_cit_tmpl.tfc_tpg_nacl_base_cit); + &tf->tf_tpg_nacl_base_cit); config_group_init_type_name(&se_nacl->acl_attrib_group, "attrib", - &tf->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit); + &tf->tf_tpg_nacl_attrib_cit); config_group_init_type_name(&se_nacl->acl_auth_group, "auth", - &tf->tf_cit_tmpl.tfc_tpg_nacl_auth_cit); + &tf->tf_tpg_nacl_auth_cit); config_group_init_type_name(&se_nacl->acl_param_group, "param", - &tf->tf_cit_tmpl.tfc_tpg_nacl_param_cit); + &tf->tf_tpg_nacl_param_cit); config_group_init_type_name(&se_nacl->acl_fabric_stat_group, - "fabric_statistics", - &tf->tf_cit_tmpl.tfc_tpg_nacl_stat_cit); + "fabric_statistics", &tf->tf_tpg_nacl_stat_cit); return &se_nacl->acl_group; } @@ -614,7 +611,7 @@ static struct config_group *target_fabric_make_np( se_tpg_np->tpg_np_parent = se_tpg; config_group_init_type_name(&se_tpg_np->tpg_np_group, name, - &tf->tf_cit_tmpl.tfc_tpg_np_base_cit); + &tf->tf_tpg_np_base_cit); return &se_tpg_np->tpg_np_group; } @@ -918,9 +915,9 @@ static struct config_group *target_fabric_make_lun( } config_group_init_type_name(&lun->lun_group, name, - &tf->tf_cit_tmpl.tfc_tpg_port_cit); + &tf->tf_tpg_port_cit); config_group_init_type_name(&lun->port_stat_grps.stat_group, - "statistics", &tf->tf_cit_tmpl.tfc_tpg_port_stat_cit); + "statistics", &tf->tf_tpg_port_stat_cit); lun_cg->default_groups[0] = &lun->port_stat_grps.stat_group; lun_cg->default_groups[1] = NULL; @@ -1071,19 +1068,19 @@ static struct config_group *target_fabric_make_tpg( se_tpg->tpg_group.default_groups[6] = NULL; config_group_init_type_name(&se_tpg->tpg_group, name, - &tf->tf_cit_tmpl.tfc_tpg_base_cit); + &tf->tf_tpg_base_cit); config_group_init_type_name(&se_tpg->tpg_lun_group, "lun", - &tf->tf_cit_tmpl.tfc_tpg_lun_cit); + &tf->tf_tpg_lun_cit); config_group_init_type_name(&se_tpg->tpg_np_group, "np", - &tf->tf_cit_tmpl.tfc_tpg_np_cit); + &tf->tf_tpg_np_cit); config_group_init_type_name(&se_tpg->tpg_acl_group, "acls", - &tf->tf_cit_tmpl.tfc_tpg_nacl_cit); + &tf->tf_tpg_nacl_cit); config_group_init_type_name(&se_tpg->tpg_attrib_group, "attrib", - &tf->tf_cit_tmpl.tfc_tpg_attrib_cit); + &tf->tf_tpg_attrib_cit); config_group_init_type_name(&se_tpg->tpg_auth_group, "auth", - &tf->tf_cit_tmpl.tfc_tpg_auth_cit); + &tf->tf_tpg_auth_cit); config_group_init_type_name(&se_tpg->tpg_param_group, "param", - &tf->tf_cit_tmpl.tfc_tpg_param_cit); + &tf->tf_tpg_param_cit); return &se_tpg->tpg_group; } @@ -1169,10 +1166,9 @@ static struct config_group *target_fabric_make_wwn( wwn->wwn_group.default_groups[0] = &wwn->fabric_stat_group; wwn->wwn_group.default_groups[1] = NULL; - config_group_init_type_name(&wwn->wwn_group, name, - &tf->tf_cit_tmpl.tfc_tpg_cit); + config_group_init_type_name(&wwn->wwn_group, name, &tf->tf_tpg_cit); config_group_init_type_name(&wwn->fabric_stat_group, "fabric_statistics", - &tf->tf_cit_tmpl.tfc_wwn_fabric_stats_cit); + &tf->tf_wwn_fabric_stats_cit); return &wwn->wwn_group; } diff --git a/include/target/target_core_configfs.h b/include/target/target_core_configfs.h index 3f11d2ead63d..abd063b8b301 100644 --- a/include/target/target_core_configfs.h +++ b/include/target/target_core_configfs.h @@ -5,30 +5,6 @@ #define TARGET_CORE_NAME_MAX_LEN 64 #define TARGET_FABRIC_NAME_SIZE 32 -struct target_fabric_configfs_template { - struct config_item_type tfc_discovery_cit; - struct config_item_type tfc_wwn_cit; - struct config_item_type tfc_wwn_fabric_stats_cit; - struct config_item_type tfc_tpg_cit; - struct config_item_type tfc_tpg_base_cit; - struct config_item_type tfc_tpg_lun_cit; - struct config_item_type tfc_tpg_port_cit; - struct config_item_type tfc_tpg_port_stat_cit; - struct config_item_type tfc_tpg_np_cit; - struct config_item_type tfc_tpg_np_base_cit; - struct config_item_type tfc_tpg_attrib_cit; - struct config_item_type tfc_tpg_auth_cit; - struct config_item_type tfc_tpg_param_cit; - struct config_item_type tfc_tpg_nacl_cit; - struct config_item_type tfc_tpg_nacl_base_cit; - struct config_item_type tfc_tpg_nacl_attrib_cit; - struct config_item_type tfc_tpg_nacl_auth_cit; - struct config_item_type tfc_tpg_nacl_param_cit; - struct config_item_type tfc_tpg_nacl_stat_cit; - struct config_item_type tfc_tpg_mappedlun_cit; - struct config_item_type tfc_tpg_mappedlun_stat_cit; -}; - struct target_fabric_configfs { atomic_t tf_access_cnt; struct list_head tf_list; @@ -36,6 +12,26 @@ struct target_fabric_configfs { struct config_group tf_disc_group; struct config_group *tf_default_groups[2]; const struct target_core_fabric_ops *tf_ops; - struct target_fabric_configfs_template tf_cit_tmpl; -}; + struct config_item_type tf_discovery_cit; + struct config_item_type tf_wwn_cit; + struct config_item_type tf_wwn_fabric_stats_cit; + struct config_item_type tf_tpg_cit; + struct config_item_type tf_tpg_base_cit; + struct config_item_type tf_tpg_lun_cit; + struct config_item_type tf_tpg_port_cit; + struct config_item_type tf_tpg_port_stat_cit; + struct config_item_type tf_tpg_np_cit; + struct config_item_type tf_tpg_np_base_cit; + struct config_item_type tf_tpg_attrib_cit; + struct config_item_type tf_tpg_auth_cit; + struct config_item_type tf_tpg_param_cit; + struct config_item_type tf_tpg_nacl_cit; + struct config_item_type tf_tpg_nacl_base_cit; + struct config_item_type tf_tpg_nacl_attrib_cit; + struct config_item_type tf_tpg_nacl_auth_cit; + struct config_item_type tf_tpg_nacl_param_cit; + struct config_item_type tf_tpg_nacl_stat_cit; + struct config_item_type tf_tpg_mappedlun_cit; + struct config_item_type tf_tpg_mappedlun_stat_cit; +}; -- cgit v1.2.3-70-g09d2 From 7ad34a93675e9c5a65711f83c518871317adc2ee Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 3 May 2015 08:50:56 +0200 Subject: target: target_core_configfs.h is not needed in fabric drivers Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- Documentation/target/tcm_mod_builder.py | 2 -- drivers/infiniband/ulp/srpt/ib_srpt.c | 1 - drivers/scsi/qla2xxx/tcm_qla2xxx.c | 1 - drivers/target/iscsi/iscsi_target.c | 1 - drivers/target/iscsi/iscsi_target_configfs.c | 1 - drivers/target/iscsi/iscsi_target_tpg.c | 1 - drivers/target/iscsi/iscsi_target_util.c | 1 - drivers/target/loopback/tcm_loop.c | 1 - drivers/target/sbp/sbp_target.c | 1 - drivers/target/target_core_alua.c | 1 - drivers/target/target_core_fabric_lib.c | 1 - drivers/target/target_core_hba.c | 1 - drivers/target/target_core_pr.c | 1 - drivers/target/target_core_stat.c | 1 - drivers/target/target_core_tmr.c | 1 - drivers/target/target_core_transport.c | 1 - drivers/target/target_core_ua.c | 1 - drivers/target/target_core_xcopy.c | 1 - drivers/target/tcm_fc/tfc_cmd.c | 1 - drivers/target/tcm_fc/tfc_conf.c | 1 - drivers/target/tcm_fc/tfc_io.c | 1 - drivers/target/tcm_fc/tfc_sess.c | 1 - drivers/usb/gadget/legacy/tcm_usb_gadget.c | 1 - drivers/vhost/scsi.c | 1 - drivers/xen/xen-scsiback.c | 1 - 25 files changed, 26 deletions(-) (limited to 'drivers') diff --git a/Documentation/target/tcm_mod_builder.py b/Documentation/target/tcm_mod_builder.py index 71e1f5863310..c70b193ec110 100755 --- a/Documentation/target/tcm_mod_builder.py +++ b/Documentation/target/tcm_mod_builder.py @@ -203,7 +203,6 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += "#include \n" buf += "#include \n" buf += "#include \n" - buf += "#include \n" buf += "#include \n\n" buf += "#include \"" + fabric_mod_name + "_base.h\"\n" buf += "#include \"" + fabric_mod_name + "_fabric.h\"\n\n" @@ -417,7 +416,6 @@ def tcm_mod_dump_fabric_ops(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += "#include \n\n" buf += "#include \n" buf += "#include \n" - buf += "#include \n\n" buf += "#include \"" + fabric_mod_name + "_base.h\"\n" buf += "#include \"" + fabric_mod_name + "_fabric.h\"\n\n" diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index f21a5f6bf858..dbad5c67a294 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -46,7 +46,6 @@ #include #include #include -#include #include "ib_srpt.h" /* Name of this kernel module. */ diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 8e331220adda..b505e5e7c987 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -43,7 +43,6 @@ #include #include #include -#include #include #include "qla_def.h" diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 3c4431f71158..1817922fe0f1 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include "iscsi_target_parameters.h" diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index aa4fc4d8e176..523ae556e22c 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c index dcb7ede1d4aa..d4ac31fc2acd 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.c +++ b/drivers/target/iscsi/iscsi_target_tpg.c @@ -18,7 +18,6 @@ #include #include -#include #include #include "iscsi_target_erl0.h" diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index c1582e88191e..a2bff0702eb2 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 07d3b52c88eb..b0c17614493e 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -35,7 +35,6 @@ #include #include #include -#include #include "tcm_loop.h" diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index 2916a4023e71..5d7755edc668 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #include diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 4f8d4d459aa4..b590f153a7b6 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -35,7 +35,6 @@ #include #include #include -#include #include "target_core_internal.h" #include "target_core_alua.h" diff --git a/drivers/target/target_core_fabric_lib.c b/drivers/target/target_core_fabric_lib.c index 89720b2f37c2..92346f23ab45 100644 --- a/drivers/target/target_core_fabric_lib.c +++ b/drivers/target/target_core_fabric_lib.c @@ -39,7 +39,6 @@ #include #include -#include #include "target_core_internal.h" #include "target_core_pr.h" diff --git a/drivers/target/target_core_hba.c b/drivers/target/target_core_hba.c index ff95f95dcd13..e6e496ff9546 100644 --- a/drivers/target/target_core_hba.c +++ b/drivers/target/target_core_hba.c @@ -36,7 +36,6 @@ #include #include #include -#include #include "target_core_internal.h" diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index d396b3b87025..a4b9a0dd50cd 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -35,7 +35,6 @@ #include #include #include -#include #include "target_core_internal.h" #include "target_core_pr.h" diff --git a/drivers/target/target_core_stat.c b/drivers/target/target_core_stat.c index 03538994d2f7..64efee2fba52 100644 --- a/drivers/target/target_core_stat.c +++ b/drivers/target/target_core_stat.c @@ -40,7 +40,6 @@ #include #include #include -#include #include #include "target_core_internal.h" diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c index 393aca8bb3eb..60ef1043242e 100644 --- a/drivers/target/target_core_tmr.c +++ b/drivers/target/target_core_tmr.c @@ -33,7 +33,6 @@ #include #include #include -#include #include "target_core_internal.h" #include "target_core_alua.h" diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 0d8662bb470e..fc460f1b0b75 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -44,7 +44,6 @@ #include #include #include -#include #include "target_core_internal.h" #include "target_core_alua.h" diff --git a/drivers/target/target_core_ua.c b/drivers/target/target_core_ua.c index 1738b1646988..a0bf0d1a3df7 100644 --- a/drivers/target/target_core_ua.c +++ b/drivers/target/target_core_ua.c @@ -30,7 +30,6 @@ #include #include -#include #include "target_core_internal.h" #include "target_core_alua.h" diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c index 5545619d3045..3556a9dcee46 100644 --- a/drivers/target/target_core_xcopy.c +++ b/drivers/target/target_core_xcopy.c @@ -32,7 +32,6 @@ #include #include #include -#include #include "target_core_internal.h" #include "target_core_pr.h" diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c index a8fe6ed5262f..d62282fb2b5b 100644 --- a/drivers/target/tcm_fc/tfc_cmd.c +++ b/drivers/target/tcm_fc/tfc_cmd.c @@ -40,7 +40,6 @@ #include #include -#include #include #include "tcm_fc.h" diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c index f0821967f0a1..ee5653139417 100644 --- a/drivers/target/tcm_fc/tfc_conf.c +++ b/drivers/target/tcm_fc/tfc_conf.c @@ -43,7 +43,6 @@ #include #include #include -#include #include #include "tcm_fc.h" diff --git a/drivers/target/tcm_fc/tfc_io.c b/drivers/target/tcm_fc/tfc_io.c index 583e755d8091..401ce7f27863 100644 --- a/drivers/target/tcm_fc/tfc_io.c +++ b/drivers/target/tcm_fc/tfc_io.c @@ -48,7 +48,6 @@ #include #include -#include #include #include "tcm_fc.h" diff --git a/drivers/target/tcm_fc/tfc_sess.c b/drivers/target/tcm_fc/tfc_sess.c index ccee7e332a4d..96a2273667ce 100644 --- a/drivers/target/tcm_fc/tfc_sess.c +++ b/drivers/target/tcm_fc/tfc_sess.c @@ -40,7 +40,6 @@ #include #include -#include #include #include "tcm_fc.h" diff --git a/drivers/usb/gadget/legacy/tcm_usb_gadget.c b/drivers/usb/gadget/legacy/tcm_usb_gadget.c index a000d89dc78a..16b9a16678fe 100644 --- a/drivers/usb/gadget/legacy/tcm_usb_gadget.c +++ b/drivers/usb/gadget/legacy/tcm_usb_gadget.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index 4a003948b07f..dcd228b59ded 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index ea929baf7ad0..edd0379c06b9 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -56,7 +56,6 @@ #include #include -#include #include #include -- cgit v1.2.3-70-g09d2 From afe92323f9df4a2c4a093cd3f2a3f82800498596 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 3 May 2015 08:54:42 +0200 Subject: target: remove ->put_session method The only instance of ->put_session is in qla2xxx, and was added by commit aaf68b ("tcm_qla2xxx: Convert to TFO->put_session() usage") with the following description: This patch converts tcm_qla2xxx code to use an internal kref_put() for se_session->sess_kref in order to ensure that qla_hw_data->hardware_lock can be held while calling qlt_unreg_sess() for the final put. But these day we're already holding the hardware lock over qlt_unreg_sess in the ->close_session callback, so we're fine without this method. (Re-add missing tcm_qla2xxx_release_session + drop put_session usage - nab) Signed-off-by: Christoph Hellwig Acked-by: Himanshu Madhani Signed-off-by: Nicholas Bellinger --- drivers/scsi/qla2xxx/tcm_qla2xxx.c | 13 ------------- drivers/target/target_core_transport.c | 6 ------ drivers/xen/xen-scsiback.c | 1 - include/target/target_core_fabric.h | 1 - 4 files changed, 21 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index b505e5e7c987..cb53144c72d0 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -700,17 +700,6 @@ static void tcm_qla2xxx_release_session(struct kref *kref) qlt_unreg_sess(se_sess->fabric_sess_ptr); } -static void tcm_qla2xxx_put_session(struct se_session *se_sess) -{ - struct qla_tgt_sess *sess = se_sess->fabric_sess_ptr; - struct qla_hw_data *ha = sess->vha->hw; - unsigned long flags; - - spin_lock_irqsave(&ha->hardware_lock, flags); - kref_put(&se_sess->sess_kref, tcm_qla2xxx_release_session); - spin_unlock_irqrestore(&ha->hardware_lock, flags); -} - static void tcm_qla2xxx_put_sess(struct qla_tgt_sess *sess) { if (!sess) @@ -1843,7 +1832,6 @@ static const struct target_core_fabric_ops tcm_qla2xxx_ops = { .tpg_get_inst_index = tcm_qla2xxx_tpg_get_inst_index, .check_stop_free = tcm_qla2xxx_check_stop_free, .release_cmd = tcm_qla2xxx_release_cmd, - .put_session = tcm_qla2xxx_put_session, .shutdown_session = tcm_qla2xxx_shutdown_session, .close_session = tcm_qla2xxx_close_session, .sess_get_index = tcm_qla2xxx_sess_get_index, @@ -1887,7 +1875,6 @@ static const struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = { .tpg_get_inst_index = tcm_qla2xxx_tpg_get_inst_index, .check_stop_free = tcm_qla2xxx_check_stop_free, .release_cmd = tcm_qla2xxx_release_cmd, - .put_session = tcm_qla2xxx_put_session, .shutdown_session = tcm_qla2xxx_shutdown_session, .close_session = tcm_qla2xxx_close_session, .sess_get_index = tcm_qla2xxx_sess_get_index, diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index fc460f1b0b75..3c2809cd8b5b 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -409,12 +409,6 @@ EXPORT_SYMBOL(target_get_session); void target_put_session(struct se_session *se_sess) { - struct se_portal_group *tpg = se_sess->se_tpg; - - if (tpg->se_tpg_tfo->put_session != NULL) { - tpg->se_tpg_tfo->put_session(se_sess); - return; - } kref_put(&se_sess->sess_kref, target_release_session); } EXPORT_SYMBOL(target_put_session); diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index edd0379c06b9..8b7dd47abd8d 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -1817,7 +1817,6 @@ static const struct target_core_fabric_ops scsiback_ops = { .tpg_get_inst_index = scsiback_tpg_get_inst_index, .check_stop_free = scsiback_check_stop_free, .release_cmd = scsiback_release_cmd, - .put_session = NULL, .shutdown_session = scsiback_shutdown_session, .close_session = scsiback_close_session, .sess_get_index = scsiback_sess_get_index, diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index f64d493f888b..55654c90350d 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -37,7 +37,6 @@ struct target_core_fabric_ops { */ int (*check_stop_free)(struct se_cmd *); void (*release_cmd)(struct se_cmd *); - void (*put_session)(struct se_session *); /* * Called with spin_lock_bh(struct se_portal_group->session_lock held. */ -- cgit v1.2.3-70-g09d2 From 3a40dede1f0af77fd4d77017a4ee07703fad87ef Mon Sep 17 00:00:00 2001 From: Christophe Vu-Brugier Date: Mon, 4 May 2015 11:33:33 +0200 Subject: target: fix a log message in se_dev_set_emulate_rest_reord() Signed-off-by: Christophe Vu-Brugier Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 9ee194d1cd4b..371a9770f563 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -1071,7 +1071,7 @@ EXPORT_SYMBOL(se_dev_set_is_nonrot); int se_dev_set_emulate_rest_reord(struct se_device *dev, int flag) { if (flag != 0) { - printk(KERN_ERR "dev[%p]: SE Device emulatation of restricted" + printk(KERN_ERR "dev[%p]: SE Device emulation of restricted" " reordering not implemented\n", dev); return -ENOSYS; } -- cgit v1.2.3-70-g09d2 From d2c27f0d0b7eb18f40b9b1a0d793c8ba074e5c23 Mon Sep 17 00:00:00 2001 From: Christophe Vu-Brugier Date: Mon, 4 May 2015 11:33:34 +0200 Subject: iscsi-target: fix variable name typo in iscsi_check_acceptor_state() Signed-off-by: Christophe Vu-Brugier Signed-off-by: Nicholas Bellinger --- drivers/target/iscsi/iscsi_target_parameters.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c index be336df0a887..e8a52f7d6204 100644 --- a/drivers/target/iscsi/iscsi_target_parameters.c +++ b/drivers/target/iscsi/iscsi_target_parameters.c @@ -967,7 +967,7 @@ static int iscsi_check_acceptor_state(struct iscsi_param *param, char *value, struct iscsi_conn *conn) { u8 acceptor_boolean_value = 0, proposer_boolean_value = 0; - char *negoitated_value = NULL; + char *negotiated_value = NULL; if (IS_PSTATE_ACCEPTOR(param)) { pr_err("Received key \"%s\" twice, protocol error.\n", @@ -1068,15 +1068,15 @@ static int iscsi_check_acceptor_state(struct iscsi_param *param, char *value, param->name, param->value); } } else if (IS_TYPE_VALUE_LIST(param)) { - negoitated_value = iscsi_check_valuelist_for_support( + negotiated_value = iscsi_check_valuelist_for_support( param, value); - if (!negoitated_value) { + if (!negotiated_value) { pr_err("Proposer's value list \"%s\" contains" " no valid values from Acceptor's value list" " \"%s\".\n", value, param->value); return -1; } - if (iscsi_update_param_value(param, negoitated_value) < 0) + if (iscsi_update_param_value(param, negotiated_value) < 0) return -1; } else if (IS_PHASE_DECLARATIVE(param)) { if (iscsi_update_param_value(param, value) < 0) -- cgit v1.2.3-70-g09d2 From 29a05deebf6c2e3010934fb78ee65cab3d329470 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Sun, 22 Mar 2015 20:42:19 -0700 Subject: target: Convert se_node_acl->device_list[] to RCU hlist This patch converts se_node_acl->device_list[] table for mappedluns to modern RCU hlist_head usage in order to support an arbitrary number of node_acl lun mappings. It converts transport_lookup_*_lun() fast-path code to use RCU read path primitives when looking up se_dev_entry. It adds a new hlist_head at se_node_acl->lun_entry_hlist for this purpose. For transport_lookup_cmd_lun() code, it works with existing per-cpu se_lun->lun_ref when associating se_cmd with se_lun + se_device. Also, go ahead and update core_create_device_list_for_node() + core_free_device_list_for_node() to use ->lun_entry_hlist. It also converts se_dev_entry->pr_ref_count access to use modern struct kref counting, and updates core_disable_device_list_for_node() to kref_put() and block on se_deve->pr_comp waiting for outstanding PR special-case PR references to drop, then invoke kfree_rcu() to wait for the RCU grace period to complete before releasing memory. So now that se_node_acl->lun_entry_hlist fast path access uses RCU protected pointers, go ahead and convert remaining non-fast path RCU updater code using ->lun_entry_lock to struct mutex to allow callers to block while walking se_node_acl->lun_entry_hlist. Finally drop the left-over core_clear_initiator_node_from_tpg() that originally cleared lun_access during se_node_acl shutdown, as post RCU conversion it now becomes duplicated logic. Reviewed-by: Hannes Reinecke Cc: Christoph Hellwig Cc: Sagi Grimberg Cc: Paul E. McKenney Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_alua.c | 3 +- drivers/target/target_core_device.c | 356 ++++++++++++++------------- drivers/target/target_core_fabric_configfs.c | 43 ++-- drivers/target/target_core_internal.h | 8 +- drivers/target/target_core_pr.c | 72 +++--- drivers/target/target_core_pscsi.c | 7 +- drivers/target/target_core_spc.c | 18 +- drivers/target/target_core_stat.c | 197 +++++++-------- drivers/target/target_core_tpg.c | 75 +----- drivers/target/target_core_ua.c | 51 ++-- include/target/target_core_backend.h | 2 +- include/target/target_core_base.h | 27 +- 12 files changed, 415 insertions(+), 444 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index b590f153a7b6..53cdfabac861 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -1001,7 +1001,8 @@ static void core_alua_do_transition_tg_pt_work(struct work_struct *work) spin_lock_bh(&port->sep_alua_lock); list_for_each_entry(se_deve, &port->sep_alua_list, alua_port_list) { - lacl = se_deve->se_lun_acl; + lacl = rcu_dereference_check(se_deve->se_lun_acl, + lockdep_is_held(&port->sep_alua_lock)); /* * se_deve->se_lun_acl pointer may be NULL for a * entry created without explicit Node+MappedLUN ACLs diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 371a9770f563..e44e6bd66659 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -60,18 +60,17 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd, u32 unpacked_lun) { struct se_lun *se_lun = NULL; struct se_session *se_sess = se_cmd->se_sess; + struct se_node_acl *nacl = se_sess->se_node_acl; struct se_device *dev; - unsigned long flags; + struct se_dev_entry *deve; if (unpacked_lun >= TRANSPORT_MAX_LUNS_PER_TPG) return TCM_NON_EXISTENT_LUN; - spin_lock_irqsave(&se_sess->se_node_acl->device_list_lock, flags); - se_cmd->se_deve = se_sess->se_node_acl->device_list[unpacked_lun]; - if (se_cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) { - struct se_dev_entry *deve = se_cmd->se_deve; - - deve->total_cmds++; + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, unpacked_lun); + if (deve) { + atomic_long_inc(&deve->total_cmds); if ((se_cmd->data_direction == DMA_TO_DEVICE) && (deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY)) { @@ -79,17 +78,19 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd, u32 unpacked_lun) " Access for 0x%08x\n", se_cmd->se_tfo->get_fabric_name(), unpacked_lun); - spin_unlock_irqrestore(&se_sess->se_node_acl->device_list_lock, flags); + rcu_read_unlock(); return TCM_WRITE_PROTECTED; } if (se_cmd->data_direction == DMA_TO_DEVICE) - deve->write_bytes += se_cmd->data_length; + atomic_long_add(se_cmd->data_length, + &deve->write_bytes); else if (se_cmd->data_direction == DMA_FROM_DEVICE) - deve->read_bytes += se_cmd->data_length; + atomic_long_add(se_cmd->data_length, + &deve->read_bytes); - se_lun = deve->se_lun; - se_cmd->se_lun = deve->se_lun; + se_lun = rcu_dereference(deve->se_lun); + se_cmd->se_lun = rcu_dereference(deve->se_lun); se_cmd->pr_res_key = deve->pr_res_key; se_cmd->orig_fe_lun = unpacked_lun; se_cmd->se_cmd_flags |= SCF_SE_LUN_CMD; @@ -97,7 +98,7 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd, u32 unpacked_lun) percpu_ref_get(&se_lun->lun_ref); se_cmd->lun_ref_active = true; } - spin_unlock_irqrestore(&se_sess->se_node_acl->device_list_lock, flags); + rcu_read_unlock(); if (!se_lun) { /* @@ -147,24 +148,23 @@ int transport_lookup_tmr_lun(struct se_cmd *se_cmd, u32 unpacked_lun) struct se_dev_entry *deve; struct se_lun *se_lun = NULL; struct se_session *se_sess = se_cmd->se_sess; + struct se_node_acl *nacl = se_sess->se_node_acl; struct se_tmr_req *se_tmr = se_cmd->se_tmr_req; unsigned long flags; if (unpacked_lun >= TRANSPORT_MAX_LUNS_PER_TPG) return -ENODEV; - spin_lock_irqsave(&se_sess->se_node_acl->device_list_lock, flags); - se_cmd->se_deve = se_sess->se_node_acl->device_list[unpacked_lun]; - deve = se_cmd->se_deve; - - if (deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) { - se_tmr->tmr_lun = deve->se_lun; - se_cmd->se_lun = deve->se_lun; - se_lun = deve->se_lun; + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, unpacked_lun); + if (deve) { + se_tmr->tmr_lun = rcu_dereference(deve->se_lun); + se_cmd->se_lun = rcu_dereference(deve->se_lun); + se_lun = rcu_dereference(deve->se_lun); se_cmd->pr_res_key = deve->pr_res_key; se_cmd->orig_fe_lun = unpacked_lun; } - spin_unlock_irqrestore(&se_sess->se_node_acl->device_list_lock, flags); + rcu_read_unlock(); if (!se_lun) { pr_debug("TARGET_CORE[%s]: Detected NON_EXISTENT_LUN" @@ -186,9 +186,27 @@ int transport_lookup_tmr_lun(struct se_cmd *se_cmd, u32 unpacked_lun) } EXPORT_SYMBOL(transport_lookup_tmr_lun); +bool target_lun_is_rdonly(struct se_cmd *cmd) +{ + struct se_session *se_sess = cmd->se_sess; + struct se_dev_entry *deve; + bool ret; + + if (cmd->se_lun->lun_access & TRANSPORT_LUNFLAGS_READ_ONLY) + return true; + + rcu_read_lock(); + deve = target_nacl_find_deve(se_sess->se_node_acl, cmd->orig_fe_lun); + ret = (deve && deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY); + rcu_read_unlock(); + + return ret; +} +EXPORT_SYMBOL(target_lun_is_rdonly); + /* * This function is called from core_scsi3_emulate_pro_register_and_move() - * and core_scsi3_decode_spec_i_port(), and will increment &deve->pr_ref_count + * and core_scsi3_decode_spec_i_port(), and will increment &deve->pr_kref * when a matching rtpi is found. */ struct se_dev_entry *core_get_se_deve_from_rtpi( @@ -197,81 +215,43 @@ struct se_dev_entry *core_get_se_deve_from_rtpi( { struct se_dev_entry *deve; struct se_lun *lun; - struct se_port *port; struct se_portal_group *tpg = nacl->se_tpg; - u32 i; - - spin_lock_irq(&nacl->device_list_lock); - for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { - deve = nacl->device_list[i]; - - if (!(deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS)) - continue; - lun = deve->se_lun; + rcu_read_lock(); + hlist_for_each_entry_rcu(deve, &nacl->lun_entry_hlist, link) { + lun = rcu_dereference(deve->se_lun); if (!lun) { pr_err("%s device entries device pointer is" " NULL, but Initiator has access.\n", tpg->se_tpg_tfo->get_fabric_name()); continue; } - port = lun->lun_sep; - if (!port) { - pr_err("%s device entries device pointer is" - " NULL, but Initiator has access.\n", - tpg->se_tpg_tfo->get_fabric_name()); - continue; - } - if (port->sep_rtpi != rtpi) + if (lun->lun_rtpi != rtpi) continue; - atomic_inc_mb(&deve->pr_ref_count); - spin_unlock_irq(&nacl->device_list_lock); + kref_get(&deve->pr_kref); + rcu_read_unlock(); return deve; } - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_unlock(); return NULL; } -int core_free_device_list_for_node( +void core_free_device_list_for_node( struct se_node_acl *nacl, struct se_portal_group *tpg) { struct se_dev_entry *deve; - struct se_lun *lun; - u32 i; - - if (!nacl->device_list) - return 0; - spin_lock_irq(&nacl->device_list_lock); - for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { - deve = nacl->device_list[i]; - - if (!(deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS)) - continue; - - if (!deve->se_lun) { - pr_err("%s device entries device pointer is" - " NULL, but Initiator has access.\n", - tpg->se_tpg_tfo->get_fabric_name()); - continue; - } - lun = deve->se_lun; - - spin_unlock_irq(&nacl->device_list_lock); - core_disable_device_list_for_node(lun, NULL, deve->mapped_lun, - TRANSPORT_LUNFLAGS_NO_ACCESS, nacl, tpg); - spin_lock_irq(&nacl->device_list_lock); + mutex_lock(&nacl->lun_entry_mutex); + hlist_for_each_entry_rcu(deve, &nacl->lun_entry_hlist, link) { + struct se_lun *lun = rcu_dereference_check(deve->se_lun, + lockdep_is_held(&nacl->lun_entry_mutex)); + core_disable_device_list_for_node(lun, deve, nacl, tpg); } - spin_unlock_irq(&nacl->device_list_lock); - - array_free(nacl->device_list, TRANSPORT_MAX_LUNS_PER_TPG); - nacl->device_list = NULL; - - return 0; + mutex_unlock(&nacl->lun_entry_mutex); } void core_update_device_list_access( @@ -281,16 +261,40 @@ void core_update_device_list_access( { struct se_dev_entry *deve; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[mapped_lun]; - if (lun_access & TRANSPORT_LUNFLAGS_READ_WRITE) { - deve->lun_flags &= ~TRANSPORT_LUNFLAGS_READ_ONLY; - deve->lun_flags |= TRANSPORT_LUNFLAGS_READ_WRITE; - } else { - deve->lun_flags &= ~TRANSPORT_LUNFLAGS_READ_WRITE; - deve->lun_flags |= TRANSPORT_LUNFLAGS_READ_ONLY; + mutex_lock(&nacl->lun_entry_mutex); + deve = target_nacl_find_deve(nacl, mapped_lun); + if (deve) { + if (lun_access & TRANSPORT_LUNFLAGS_READ_WRITE) { + deve->lun_flags &= ~TRANSPORT_LUNFLAGS_READ_ONLY; + deve->lun_flags |= TRANSPORT_LUNFLAGS_READ_WRITE; + } else { + deve->lun_flags &= ~TRANSPORT_LUNFLAGS_READ_WRITE; + deve->lun_flags |= TRANSPORT_LUNFLAGS_READ_ONLY; + } } - spin_unlock_irq(&nacl->device_list_lock); + mutex_unlock(&nacl->lun_entry_mutex); +} + +/* + * Called with rcu_read_lock or nacl->device_list_lock held. + */ +struct se_dev_entry *target_nacl_find_deve(struct se_node_acl *nacl, u32 mapped_lun) +{ + struct se_dev_entry *deve; + + hlist_for_each_entry_rcu(deve, &nacl->lun_entry_hlist, link) + if (deve->mapped_lun == mapped_lun) + return deve; + + return NULL; +} +EXPORT_SYMBOL(target_nacl_find_deve); + +void target_pr_kref_release(struct kref *kref) +{ + struct se_dev_entry *deve = container_of(kref, struct se_dev_entry, + pr_kref); + complete(&deve->pr_comp); } /* core_enable_device_list_for_node(): @@ -306,85 +310,87 @@ int core_enable_device_list_for_node( struct se_portal_group *tpg) { struct se_port *port = lun->lun_sep; - struct se_dev_entry *deve; - - spin_lock_irq(&nacl->device_list_lock); - - deve = nacl->device_list[mapped_lun]; - - /* - * Check if the call is handling demo mode -> explicit LUN ACL - * transition. This transition must be for the same struct se_lun - * + mapped_lun that was setup in demo mode.. - */ - if (deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) { - if (deve->se_lun_acl != NULL) { - pr_err("struct se_dev_entry->se_lun_acl" - " already set for demo mode -> explicit" - " LUN ACL transition\n"); - spin_unlock_irq(&nacl->device_list_lock); + struct se_dev_entry *orig, *new; + + new = kzalloc(sizeof(*new), GFP_KERNEL); + if (!new) { + pr_err("Unable to allocate se_dev_entry memory\n"); + return -ENOMEM; + } + + atomic_set(&new->ua_count, 0); + spin_lock_init(&new->ua_lock); + INIT_LIST_HEAD(&new->alua_port_list); + INIT_LIST_HEAD(&new->ua_list); + + new->mapped_lun = mapped_lun; + kref_init(&new->pr_kref); + init_completion(&new->pr_comp); + + if (lun_access & TRANSPORT_LUNFLAGS_READ_WRITE) + new->lun_flags |= TRANSPORT_LUNFLAGS_READ_WRITE; + else + new->lun_flags |= TRANSPORT_LUNFLAGS_READ_ONLY; + + new->creation_time = get_jiffies_64(); + new->attach_count++; + + mutex_lock(&nacl->lun_entry_mutex); + orig = target_nacl_find_deve(nacl, mapped_lun); + if (orig && orig->se_lun) { + struct se_lun *orig_lun = rcu_dereference_check(orig->se_lun, + lockdep_is_held(&nacl->lun_entry_mutex)); + + if (orig_lun != lun) { + pr_err("Existing orig->se_lun doesn't match new lun" + " for dynamic -> explicit NodeACL conversion:" + " %s\n", nacl->initiatorname); + mutex_unlock(&nacl->lun_entry_mutex); + kfree(new); return -EINVAL; } - if (deve->se_lun != lun) { - pr_err("struct se_dev_entry->se_lun does" - " match passed struct se_lun for demo mode" - " -> explicit LUN ACL transition\n"); - spin_unlock_irq(&nacl->device_list_lock); - return -EINVAL; - } - deve->se_lun_acl = lun_acl; + BUG_ON(orig->se_lun_acl != NULL); - if (lun_access & TRANSPORT_LUNFLAGS_READ_WRITE) { - deve->lun_flags &= ~TRANSPORT_LUNFLAGS_READ_ONLY; - deve->lun_flags |= TRANSPORT_LUNFLAGS_READ_WRITE; - } else { - deve->lun_flags &= ~TRANSPORT_LUNFLAGS_READ_WRITE; - deve->lun_flags |= TRANSPORT_LUNFLAGS_READ_ONLY; - } + rcu_assign_pointer(new->se_lun, lun); + rcu_assign_pointer(new->se_lun_acl, lun_acl); + hlist_del_rcu(&orig->link); + hlist_add_head_rcu(&new->link, &nacl->lun_entry_hlist); + mutex_unlock(&nacl->lun_entry_mutex); - spin_unlock_irq(&nacl->device_list_lock); - return 0; - } + spin_lock_bh(&port->sep_alua_lock); + list_del(&orig->alua_port_list); + list_add_tail(&new->alua_port_list, &port->sep_alua_list); + spin_unlock_bh(&port->sep_alua_lock); - deve->se_lun = lun; - deve->se_lun_acl = lun_acl; - deve->mapped_lun = mapped_lun; - deve->lun_flags |= TRANSPORT_LUNFLAGS_INITIATOR_ACCESS; + kref_put(&orig->pr_kref, target_pr_kref_release); + wait_for_completion(&orig->pr_comp); - if (lun_access & TRANSPORT_LUNFLAGS_READ_WRITE) { - deve->lun_flags &= ~TRANSPORT_LUNFLAGS_READ_ONLY; - deve->lun_flags |= TRANSPORT_LUNFLAGS_READ_WRITE; - } else { - deve->lun_flags &= ~TRANSPORT_LUNFLAGS_READ_WRITE; - deve->lun_flags |= TRANSPORT_LUNFLAGS_READ_ONLY; + kfree_rcu(orig, rcu_head); + return 0; } - deve->creation_time = get_jiffies_64(); - deve->attach_count++; - spin_unlock_irq(&nacl->device_list_lock); + rcu_assign_pointer(new->se_lun, lun); + rcu_assign_pointer(new->se_lun_acl, lun_acl); + hlist_add_head_rcu(&new->link, &nacl->lun_entry_hlist); + mutex_unlock(&nacl->lun_entry_mutex); spin_lock_bh(&port->sep_alua_lock); - list_add_tail(&deve->alua_port_list, &port->sep_alua_list); + list_add_tail(&new->alua_port_list, &port->sep_alua_list); spin_unlock_bh(&port->sep_alua_lock); return 0; } -/* core_disable_device_list_for_node(): - * - * +/* + * Called with se_node_acl->lun_entry_mutex held. */ -int core_disable_device_list_for_node( +void core_disable_device_list_for_node( struct se_lun *lun, - struct se_lun_acl *lun_acl, - u32 mapped_lun, - u32 lun_access, + struct se_dev_entry *orig, struct se_node_acl *nacl, struct se_portal_group *tpg) { struct se_port *port = lun->lun_sep; - struct se_dev_entry *deve = nacl->device_list[mapped_lun]; - /* * If the MappedLUN entry is being disabled, the entry in * port->sep_alua_list must be removed now before clearing the @@ -399,29 +405,29 @@ int core_disable_device_list_for_node( * MappedLUN *deve will be released below.. */ spin_lock_bh(&port->sep_alua_lock); - list_del(&deve->alua_port_list); + list_del(&orig->alua_port_list); spin_unlock_bh(&port->sep_alua_lock); /* - * Wait for any in process SPEC_I_PT=1 or REGISTER_AND_MOVE - * PR operation to complete. + * Disable struct se_dev_entry LUN ACL mapping */ - while (atomic_read(&deve->pr_ref_count) != 0) - cpu_relax(); - - spin_lock_irq(&nacl->device_list_lock); + core_scsi3_ua_release_all(orig); + + hlist_del_rcu(&orig->link); + rcu_assign_pointer(orig->se_lun, NULL); + rcu_assign_pointer(orig->se_lun_acl, NULL); + orig->lun_flags = 0; + orig->creation_time = 0; + orig->attach_count--; /* - * Disable struct se_dev_entry LUN ACL mapping + * Before firing off RCU callback, wait for any in process SPEC_I_PT=1 + * or REGISTER_AND_MOVE PR operation to complete. */ - core_scsi3_ua_release_all(deve); - deve->se_lun = NULL; - deve->se_lun_acl = NULL; - deve->lun_flags = 0; - deve->creation_time = 0; - deve->attach_count--; - spin_unlock_irq(&nacl->device_list_lock); + kref_put(&orig->pr_kref, target_pr_kref_release); + wait_for_completion(&orig->pr_comp); + + kfree_rcu(orig, rcu_head); core_scsi3_free_pr_reg_from_nacl(lun->lun_se_dev, nacl); - return 0; } /* core_clear_lun_from_tpg(): @@ -432,26 +438,22 @@ void core_clear_lun_from_tpg(struct se_lun *lun, struct se_portal_group *tpg) { struct se_node_acl *nacl; struct se_dev_entry *deve; - u32 i; spin_lock_irq(&tpg->acl_node_lock); list_for_each_entry(nacl, &tpg->acl_node_list, acl_list) { spin_unlock_irq(&tpg->acl_node_lock); - spin_lock_irq(&nacl->device_list_lock); - for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { - deve = nacl->device_list[i]; - if (lun != deve->se_lun) - continue; - spin_unlock_irq(&nacl->device_list_lock); + mutex_lock(&nacl->lun_entry_mutex); + hlist_for_each_entry_rcu(deve, &nacl->lun_entry_hlist, link) { + struct se_lun *tmp_lun = rcu_dereference_check(deve->se_lun, + lockdep_is_held(&nacl->lun_entry_mutex)); - core_disable_device_list_for_node(lun, NULL, - deve->mapped_lun, TRANSPORT_LUNFLAGS_NO_ACCESS, - nacl, tpg); + if (lun != tmp_lun) + continue; - spin_lock_irq(&nacl->device_list_lock); + core_disable_device_list_for_node(lun, deve, nacl, tpg); } - spin_unlock_irq(&nacl->device_list_lock); + mutex_unlock(&nacl->lun_entry_mutex); spin_lock_irq(&tpg->acl_node_lock); } @@ -583,7 +585,9 @@ int core_dev_export( if (IS_ERR(port)) return PTR_ERR(port); + lun->lun_index = dev->dev_index; lun->lun_se_dev = dev; + lun->lun_rtpi = port->sep_rtpi; spin_lock(&hba->device_lock); dev->export_count++; @@ -1369,16 +1373,13 @@ int core_dev_add_initiator_node_lun_acl( return 0; } -/* core_dev_del_initiator_node_lun_acl(): - * - * - */ int core_dev_del_initiator_node_lun_acl( struct se_portal_group *tpg, struct se_lun *lun, struct se_lun_acl *lacl) { struct se_node_acl *nacl; + struct se_dev_entry *deve; nacl = lacl->se_lun_nacl; if (!nacl) @@ -1389,8 +1390,11 @@ int core_dev_del_initiator_node_lun_acl( atomic_dec_mb(&lun->lun_acl_count); spin_unlock(&lun->lun_acl_lock); - core_disable_device_list_for_node(lun, NULL, lacl->mapped_lun, - TRANSPORT_LUNFLAGS_NO_ACCESS, nacl, tpg); + mutex_lock(&nacl->lun_entry_mutex); + deve = target_nacl_find_deve(nacl, lacl->mapped_lun); + if (deve) + core_disable_device_list_for_node(lun, deve, nacl, tpg); + mutex_unlock(&nacl->lun_entry_mutex); lacl->se_lun = NULL; diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index 6cb4828308e9..0939a5492c16 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -123,16 +123,16 @@ static int target_fabric_mappedlun_link( * which be will write protected (READ-ONLY) when * tpg_1/attrib/demo_mode_write_protect=1 */ - spin_lock_irq(&lacl->se_lun_nacl->device_list_lock); - deve = lacl->se_lun_nacl->device_list[lacl->mapped_lun]; - if (deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) + rcu_read_lock(); + deve = target_nacl_find_deve(lacl->se_lun_nacl, lacl->mapped_lun); + if (deve) lun_access = deve->lun_flags; else lun_access = (se_tpg->se_tpg_tfo->tpg_check_prod_mode_write_protect( se_tpg)) ? TRANSPORT_LUNFLAGS_READ_ONLY : TRANSPORT_LUNFLAGS_READ_WRITE; - spin_unlock_irq(&lacl->se_lun_nacl->device_list_lock); + rcu_read_unlock(); /* * Determine the actual mapped LUN value user wants.. * @@ -149,23 +149,13 @@ static int target_fabric_mappedlun_unlink( struct config_item *lun_acl_ci, struct config_item *lun_ci) { - struct se_lun *lun; struct se_lun_acl *lacl = container_of(to_config_group(lun_acl_ci), struct se_lun_acl, se_lun_group); - struct se_node_acl *nacl = lacl->se_lun_nacl; - struct se_dev_entry *deve = nacl->device_list[lacl->mapped_lun]; - struct se_portal_group *se_tpg; - /* - * Determine if the underlying MappedLUN has already been released.. - */ - if (!deve->se_lun) - return 0; - - lun = container_of(to_config_group(lun_ci), struct se_lun, lun_group); - se_tpg = lun->lun_sep->sep_tpg; + struct se_lun *lun = container_of(to_config_group(lun_ci), + struct se_lun, lun_group); + struct se_portal_group *se_tpg = lun->lun_sep->sep_tpg; - core_dev_del_initiator_node_lun_acl(se_tpg, lun, lacl); - return 0; + return core_dev_del_initiator_node_lun_acl(se_tpg, lun, lacl); } CONFIGFS_EATTR_STRUCT(target_fabric_mappedlun, se_lun_acl); @@ -181,14 +171,15 @@ static ssize_t target_fabric_mappedlun_show_write_protect( { struct se_node_acl *se_nacl = lacl->se_lun_nacl; struct se_dev_entry *deve; - ssize_t len; - - spin_lock_irq(&se_nacl->device_list_lock); - deve = se_nacl->device_list[lacl->mapped_lun]; - len = sprintf(page, "%d\n", - (deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY) ? - 1 : 0); - spin_unlock_irq(&se_nacl->device_list_lock); + ssize_t len = 0; + + rcu_read_lock(); + deve = target_nacl_find_deve(se_nacl, lacl->mapped_lun); + if (deve) { + len = sprintf(page, "%d\n", + (deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY) ? 1 : 0); + } + rcu_read_unlock(); return len; } diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index d0344ad9b0d8..a04a6e396ae3 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -9,13 +9,15 @@ extern struct mutex g_device_mutex; extern struct list_head g_device_list; struct se_dev_entry *core_get_se_deve_from_rtpi(struct se_node_acl *, u16); -int core_free_device_list_for_node(struct se_node_acl *, +void target_pr_kref_release(struct kref *); +void core_free_device_list_for_node(struct se_node_acl *, struct se_portal_group *); void core_update_device_list_access(u32, u32, struct se_node_acl *); +struct se_dev_entry *target_nacl_find_deve(struct se_node_acl *, u32); int core_enable_device_list_for_node(struct se_lun *, struct se_lun_acl *, u32, u32, struct se_node_acl *, struct se_portal_group *); -int core_disable_device_list_for_node(struct se_lun *, struct se_lun_acl *, - u32, u32, struct se_node_acl *, struct se_portal_group *); +void core_disable_device_list_for_node(struct se_lun *, struct se_dev_entry *, + struct se_node_acl *, struct se_portal_group *); void core_clear_lun_from_tpg(struct se_lun *, struct se_portal_group *); int core_dev_export(struct se_device *, struct se_portal_group *, struct se_lun *); diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index a4b9a0dd50cd..909573a682d5 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -48,7 +48,7 @@ struct pr_transport_id_holder { struct t10_pr_registration *dest_pr_reg; struct se_portal_group *dest_tpg; struct se_node_acl *dest_node_acl; - struct se_dev_entry *dest_se_deve; + struct se_dev_entry __rcu *dest_se_deve; struct list_head dest_list; }; @@ -232,7 +232,7 @@ target_scsi2_reservation_release(struct se_cmd *cmd) tpg = sess->se_tpg; pr_debug("SCSI-2 Released reservation for %s LUN: %u ->" " MAPPED LUN: %u for %s\n", tpg->se_tpg_tfo->get_fabric_name(), - cmd->se_lun->unpacked_lun, cmd->se_deve->mapped_lun, + cmd->se_lun->unpacked_lun, cmd->orig_fe_lun, sess->se_node_acl->initiatorname); out_unlock: @@ -281,7 +281,7 @@ target_scsi2_reservation_reserve(struct se_cmd *cmd) dev->dev_reserved_node_acl->initiatorname); pr_err("Current attempt - LUN: %u -> MAPPED LUN: %u" " from %s \n", cmd->se_lun->unpacked_lun, - cmd->se_deve->mapped_lun, + cmd->orig_fe_lun, sess->se_node_acl->initiatorname); ret = TCM_RESERVATION_CONFLICT; goto out_unlock; @@ -295,7 +295,7 @@ target_scsi2_reservation_reserve(struct se_cmd *cmd) } pr_debug("SCSI-2 Reserved %s LUN: %u -> MAPPED LUN: %u" " for %s\n", tpg->se_tpg_tfo->get_fabric_name(), - cmd->se_lun->unpacked_lun, cmd->se_deve->mapped_lun, + cmd->se_lun->unpacked_lun, cmd->orig_fe_lun, sess->se_node_acl->initiatorname); out_unlock: @@ -320,6 +320,7 @@ static int core_scsi3_pr_seq_non_holder( unsigned char *cdb = cmd->t_task_cdb; struct se_dev_entry *se_deve; struct se_session *se_sess = cmd->se_sess; + struct se_node_acl *nacl = se_sess->se_node_acl; int other_cdb = 0, ignore_reg; int registered_nexus = 0, ret = 1; /* Conflict by default */ int all_reg = 0, reg_only = 0; /* ALL_REG, REG_ONLY */ @@ -327,7 +328,8 @@ static int core_scsi3_pr_seq_non_holder( int legacy = 0; /* Act like a legacy device and return * RESERVATION CONFLICT on some CDBs */ - se_deve = se_sess->se_node_acl->device_list[cmd->orig_fe_lun]; + rcu_read_lock(); + se_deve = target_nacl_find_deve(nacl, cmd->orig_fe_lun); /* * Determine if the registration should be ignored due to * non-matching ISIDs in target_scsi3_pr_reservation_check(). @@ -368,8 +370,10 @@ static int core_scsi3_pr_seq_non_holder( registered_nexus = 1; break; default: + rcu_read_unlock(); return -EINVAL; } + rcu_read_unlock(); /* * Referenced from spc4r17 table 45 for *NON* PR holder access */ @@ -735,7 +739,7 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( if (strcmp(nacl->initiatorname, nacl_tmp->initiatorname)) continue; - atomic_inc_mb(&deve_tmp->pr_ref_count); + kref_get(&deve_tmp->pr_kref); spin_unlock_bh(&port->sep_alua_lock); /* * Grab a configfs group dependency that is released @@ -748,7 +752,7 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( pr_err("core_scsi3_lunacl_depend" "_item() failed\n"); atomic_dec_mb(&port->sep_tg_pt_ref_cnt); - atomic_dec_mb(&deve_tmp->pr_ref_count); + kref_put(&deve_tmp->pr_kref, target_pr_kref_release); goto out; } /* @@ -763,7 +767,6 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( sa_res_key, all_tg_pt, aptpl); if (!pr_reg_atp) { atomic_dec_mb(&port->sep_tg_pt_ref_cnt); - atomic_dec_mb(&deve_tmp->pr_ref_count); core_scsi3_lunacl_undepend_item(deve_tmp); goto out; } @@ -896,7 +899,7 @@ static int __core_scsi3_check_aptpl_registration( struct se_lun *lun, u32 target_lun, struct se_node_acl *nacl, - struct se_dev_entry *deve) + u32 mapped_lun) { struct t10_pr_registration *pr_reg, *pr_reg_tmp; struct t10_reservation *pr_tmpl = &dev->t10_pr; @@ -924,13 +927,12 @@ static int __core_scsi3_check_aptpl_registration( pr_reg_aptpl_list) { if (!strcmp(pr_reg->pr_iport, i_port) && - (pr_reg->pr_res_mapped_lun == deve->mapped_lun) && + (pr_reg->pr_res_mapped_lun == mapped_lun) && !(strcmp(pr_reg->pr_tport, t_port)) && (pr_reg->pr_reg_tpgt == tpgt) && (pr_reg->pr_aptpl_target_lun == target_lun)) { pr_reg->pr_reg_nacl = nacl; - pr_reg->pr_reg_deve = deve; pr_reg->pr_reg_tg_pt_lun = lun; list_del(&pr_reg->pr_reg_aptpl_list); @@ -968,13 +970,12 @@ int core_scsi3_check_aptpl_registration( struct se_node_acl *nacl, u32 mapped_lun) { - struct se_dev_entry *deve = nacl->device_list[mapped_lun]; - if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS) return 0; return __core_scsi3_check_aptpl_registration(dev, tpg, lun, - lun->unpacked_lun, nacl, deve); + lun->unpacked_lun, nacl, + mapped_lun); } static void __core_scsi3_dump_registration( @@ -1408,27 +1409,29 @@ static int core_scsi3_lunacl_depend_item(struct se_dev_entry *se_deve) static void core_scsi3_lunacl_undepend_item(struct se_dev_entry *se_deve) { - struct se_lun_acl *lun_acl = se_deve->se_lun_acl; + struct se_lun_acl *lun_acl; struct se_node_acl *nacl; struct se_portal_group *tpg; /* * For nacl->dynamic_node_acl=1 */ + lun_acl = se_deve->se_lun_acl; if (!lun_acl) { - atomic_dec_mb(&se_deve->pr_ref_count); + kref_put(&se_deve->pr_kref, target_pr_kref_release); return; } nacl = lun_acl->se_lun_nacl; tpg = nacl->se_tpg; target_undepend_item(&lun_acl->se_lun_group.cg_item); - atomic_dec_mb(&se_deve->pr_ref_count); + kref_put(&se_deve->pr_kref, target_pr_kref_release); } static sense_reason_t core_scsi3_decode_spec_i_port( struct se_cmd *cmd, struct se_portal_group *tpg, + struct se_dev_entry *local_se_deve, unsigned char *l_isid, u64 sa_res_key, int all_tg_pt, @@ -1439,7 +1442,7 @@ core_scsi3_decode_spec_i_port( struct se_portal_group *dest_tpg = NULL, *tmp_tpg; struct se_session *se_sess = cmd->se_sess; struct se_node_acl *dest_node_acl = NULL; - struct se_dev_entry *dest_se_deve = NULL, *local_se_deve; + struct se_dev_entry __rcu *dest_se_deve = NULL; struct t10_pr_registration *dest_pr_reg, *local_pr_reg, *pr_reg_e; struct t10_pr_registration *pr_reg_tmp, *pr_reg_tmp_safe; LIST_HEAD(tid_dest_list); @@ -1452,7 +1455,6 @@ core_scsi3_decode_spec_i_port( int dest_local_nexus; u32 dest_rtpi = 0; - local_se_deve = se_sess->se_node_acl->device_list[cmd->orig_fe_lun]; /* * Allocate a struct pr_transport_id_holder and setup the * local_node_acl and local_se_deve pointers and add to @@ -1467,7 +1469,6 @@ core_scsi3_decode_spec_i_port( INIT_LIST_HEAD(&tidh_new->dest_list); tidh_new->dest_tpg = tpg; tidh_new->dest_node_acl = se_sess->se_node_acl; - tidh_new->dest_se_deve = local_se_deve; local_pr_reg = __core_scsi3_alloc_registration(cmd->se_dev, se_sess->se_node_acl, local_se_deve, l_isid, @@ -1476,6 +1477,7 @@ core_scsi3_decode_spec_i_port( kfree(tidh_new); return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } + rcu_assign_pointer(tidh_new->dest_se_deve, local_se_deve); tidh_new->dest_pr_reg = local_pr_reg; /* * The local I_T nexus does not hold any configfs dependances, @@ -1635,7 +1637,7 @@ core_scsi3_decode_spec_i_port( if (core_scsi3_lunacl_depend_item(dest_se_deve)) { pr_err("core_scsi3_lunacl_depend_item()" " failed\n"); - atomic_dec_mb(&dest_se_deve->pr_ref_count); + kref_put(&dest_se_deve->pr_kref, target_pr_kref_release); core_scsi3_nodeacl_undepend_item(dest_node_acl); core_scsi3_tpg_undepend_item(dest_tpg); ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; @@ -1990,6 +1992,7 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key, bool aptpl, bool all_tg_pt, bool spec_i_pt, enum register_type register_type) { struct se_session *se_sess = cmd->se_sess; + struct se_node_acl *nacl = se_sess->se_node_acl; struct se_device *dev = cmd->se_dev; struct se_dev_entry *se_deve; struct se_lun *se_lun = cmd->se_lun; @@ -2005,7 +2008,14 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key, return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } se_tpg = se_sess->se_tpg; - se_deve = se_sess->se_node_acl->device_list[cmd->orig_fe_lun]; + + rcu_read_lock(); + se_deve = target_nacl_find_deve(nacl, cmd->orig_fe_lun); + if (!se_deve) { + pr_err("Unable to locate se_deve for PRO-REGISTER\n"); + rcu_read_unlock(); + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + } if (se_tpg->se_tpg_tfo->sess_get_initiator_sid) { memset(&isid_buf[0], 0, PR_REG_ISID_LEN); @@ -2021,14 +2031,16 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key, if (res_key) { pr_warn("SPC-3 PR: Reservation Key non-zero" " for SA REGISTER, returning CONFLICT\n"); + rcu_read_unlock(); return TCM_RESERVATION_CONFLICT; } /* * Do nothing but return GOOD status. */ - if (!sa_res_key) + if (!sa_res_key) { + rcu_read_unlock(); return 0; - + } if (!spec_i_pt) { /* * Perform the Service Action REGISTER on the Initiator @@ -2041,6 +2053,7 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key, register_type, 0)) { pr_err("Unable to allocate" " struct t10_pr_registration\n"); + rcu_read_unlock(); return TCM_INVALID_PARAMETER_LIST; } } else { @@ -2052,14 +2065,17 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key, * logic from of core_scsi3_alloc_registration() for * each TransportID provided SCSI Initiator Port/Device */ - ret = core_scsi3_decode_spec_i_port(cmd, se_tpg, + ret = core_scsi3_decode_spec_i_port(cmd, se_tpg, se_deve, isid_ptr, sa_res_key, all_tg_pt, aptpl); - if (ret != 0) + if (ret != 0) { + rcu_read_unlock(); return ret; + } } - + rcu_read_unlock(); return core_scsi3_update_and_write_aptpl(dev, aptpl); } + rcu_read_unlock(); /* ok, existing registration */ @@ -3321,7 +3337,7 @@ after_iport_check: if (core_scsi3_lunacl_depend_item(dest_se_deve)) { pr_err("core_scsi3_lunacl_depend_item() failed\n"); - atomic_dec_mb(&dest_se_deve->pr_ref_count); + kref_put(&dest_se_deve->pr_kref, target_pr_kref_release); dest_se_deve = NULL; ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; goto out; diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index ecc5eaef13d6..21db991b4465 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -47,6 +47,7 @@ #include #include "target_core_alua.h" +#include "target_core_internal.h" #include "target_core_pscsi.h" #define ISPRINT(a) ((a >= ' ') && (a <= '~')) @@ -637,12 +638,14 @@ static void pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg, * Hack to make sure that Write-Protect modepage is set if R/O mode is * forced. */ - if (!cmd->se_deve || !cmd->data_length) + if (!cmd->data_length) goto after_mode_sense; if (((cdb[0] == MODE_SENSE) || (cdb[0] == MODE_SENSE_10)) && (status_byte(result) << 1) == SAM_STAT_GOOD) { - if (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY) { + bool read_only = target_lun_is_rdonly(cmd); + + if (read_only) { unsigned char *buf; buf = transport_kmap_data_sg(cmd); diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index 78c0b40fa5c0..9f995b87b8d1 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -981,6 +981,7 @@ static sense_reason_t spc_emulate_modesense(struct se_cmd *cmd) int length = 0; int ret; int i; + bool read_only = target_lun_is_rdonly(cmd);; memset(buf, 0, SE_MODE_PAGE_BUF); @@ -991,9 +992,7 @@ static sense_reason_t spc_emulate_modesense(struct se_cmd *cmd) length = ten ? 3 : 2; /* DEVICE-SPECIFIC PARAMETER */ - if ((cmd->se_lun->lun_access & TRANSPORT_LUNFLAGS_READ_ONLY) || - (cmd->se_deve && - (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY))) + if ((cmd->se_lun->lun_access & TRANSPORT_LUNFLAGS_READ_ONLY) || read_only) spc_modesense_write_protect(&buf[length], type); /* @@ -1211,8 +1210,9 @@ sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd) { struct se_dev_entry *deve; struct se_session *sess = cmd->se_sess; + struct se_node_acl *nacl; unsigned char *buf; - u32 lun_count = 0, offset = 8, i; + u32 lun_count = 0, offset = 8; if (cmd->data_length < 16) { pr_warn("REPORT LUNS allocation length %u too small\n", @@ -1234,12 +1234,10 @@ sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd) lun_count = 1; goto done; } + nacl = sess->se_node_acl; - spin_lock_irq(&sess->se_node_acl->device_list_lock); - for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { - deve = sess->se_node_acl->device_list[i]; - if (!(deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS)) - continue; + rcu_read_lock(); + hlist_for_each_entry_rcu(deve, &nacl->lun_entry_hlist, link) { /* * We determine the correct LUN LIST LENGTH even once we * have reached the initial allocation length. @@ -1252,7 +1250,7 @@ sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd) int_to_scsilun(deve->mapped_lun, (struct scsi_lun *)&buf[offset]); offset += 8; } - spin_unlock_irq(&sess->se_node_acl->device_list_lock); + rcu_read_unlock(); /* * See SPC3 r07, page 159. diff --git a/drivers/target/target_core_stat.c b/drivers/target/target_core_stat.c index 64efee2fba52..ea1287940a7c 100644 --- a/drivers/target/target_core_stat.c +++ b/drivers/target/target_core_stat.c @@ -1084,17 +1084,17 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_inst( struct se_portal_group *tpg; ssize_t ret; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[lacl->mapped_lun]; - if (!deve->se_lun || !deve->se_lun_acl) { - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, lacl->mapped_lun); + if (!deve) { + rcu_read_unlock(); return -ENODEV; } tpg = nacl->se_tpg; /* scsiInstIndex */ ret = snprintf(page, PAGE_SIZE, "%u\n", tpg->se_tpg_tfo->tpg_get_inst_index(tpg)); - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(inst); @@ -1109,16 +1109,16 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_dev( struct se_lun *lun; ssize_t ret; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[lacl->mapped_lun]; - if (!deve->se_lun || !deve->se_lun_acl) { - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, lacl->mapped_lun); + if (!deve) { + rcu_read_unlock(); return -ENODEV; } - lun = deve->se_lun; + lun = rcu_dereference(deve->se_lun); /* scsiDeviceIndex */ - ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_se_dev->dev_index); - spin_unlock_irq(&nacl->device_list_lock); + ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_index); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(dev); @@ -1133,16 +1133,16 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_port( struct se_portal_group *tpg; ssize_t ret; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[lacl->mapped_lun]; - if (!deve->se_lun || !deve->se_lun_acl) { - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, lacl->mapped_lun); + if (!deve) { + rcu_read_unlock(); return -ENODEV; } tpg = nacl->se_tpg; /* scsiAuthIntrTgtPortIndex */ ret = snprintf(page, PAGE_SIZE, "%u\n", tpg->se_tpg_tfo->tpg_get_tag(tpg)); - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(port); @@ -1156,15 +1156,15 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_indx( struct se_dev_entry *deve; ssize_t ret; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[lacl->mapped_lun]; - if (!deve->se_lun || !deve->se_lun_acl) { - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, lacl->mapped_lun); + if (!deve) { + rcu_read_unlock(); return -ENODEV; } /* scsiAuthIntrIndex */ ret = snprintf(page, PAGE_SIZE, "%u\n", nacl->acl_index); - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(indx); @@ -1178,15 +1178,15 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_dev_or_port( struct se_dev_entry *deve; ssize_t ret; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[lacl->mapped_lun]; - if (!deve->se_lun || !deve->se_lun_acl) { - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, lacl->mapped_lun); + if (!deve) { + rcu_read_unlock(); return -ENODEV; } /* scsiAuthIntrDevOrPort */ ret = snprintf(page, PAGE_SIZE, "%u\n", 1); - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(dev_or_port); @@ -1200,15 +1200,15 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_intr_name( struct se_dev_entry *deve; ssize_t ret; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[lacl->mapped_lun]; - if (!deve->se_lun || !deve->se_lun_acl) { - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, lacl->mapped_lun); + if (!deve) { + rcu_read_unlock(); return -ENODEV; } /* scsiAuthIntrName */ ret = snprintf(page, PAGE_SIZE, "%s\n", nacl->initiatorname); - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(intr_name); @@ -1222,15 +1222,15 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_map_indx( struct se_dev_entry *deve; ssize_t ret; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[lacl->mapped_lun]; - if (!deve->se_lun || !deve->se_lun_acl) { - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, lacl->mapped_lun); + if (!deve) { + rcu_read_unlock(); return -ENODEV; } /* FIXME: scsiAuthIntrLunMapIndex */ ret = snprintf(page, PAGE_SIZE, "%u\n", 0); - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(map_indx); @@ -1244,15 +1244,15 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_att_count( struct se_dev_entry *deve; ssize_t ret; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[lacl->mapped_lun]; - if (!deve->se_lun || !deve->se_lun_acl) { - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, lacl->mapped_lun); + if (!deve) { + rcu_read_unlock(); return -ENODEV; } /* scsiAuthIntrAttachedTimes */ ret = snprintf(page, PAGE_SIZE, "%u\n", deve->attach_count); - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(att_count); @@ -1266,15 +1266,16 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_num_cmds( struct se_dev_entry *deve; ssize_t ret; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[lacl->mapped_lun]; - if (!deve->se_lun || !deve->se_lun_acl) { - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, lacl->mapped_lun); + if (!deve) { + rcu_read_unlock(); return -ENODEV; } /* scsiAuthIntrOutCommands */ - ret = snprintf(page, PAGE_SIZE, "%u\n", deve->total_cmds); - spin_unlock_irq(&nacl->device_list_lock); + ret = snprintf(page, PAGE_SIZE, "%lu\n", + atomic_long_read(&deve->total_cmds)); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(num_cmds); @@ -1288,15 +1289,16 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_read_mbytes( struct se_dev_entry *deve; ssize_t ret; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[lacl->mapped_lun]; - if (!deve->se_lun || !deve->se_lun_acl) { - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, lacl->mapped_lun); + if (!deve) { + rcu_read_unlock(); return -ENODEV; } /* scsiAuthIntrReadMegaBytes */ - ret = snprintf(page, PAGE_SIZE, "%u\n", (u32)(deve->read_bytes >> 20)); - spin_unlock_irq(&nacl->device_list_lock); + ret = snprintf(page, PAGE_SIZE, "%u\n", + (u32)(atomic_long_read(&deve->read_bytes) >> 20)); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(read_mbytes); @@ -1310,15 +1312,16 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_write_mbytes( struct se_dev_entry *deve; ssize_t ret; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[lacl->mapped_lun]; - if (!deve->se_lun || !deve->se_lun_acl) { - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, lacl->mapped_lun); + if (!deve) { + rcu_read_unlock(); return -ENODEV; } /* scsiAuthIntrWrittenMegaBytes */ - ret = snprintf(page, PAGE_SIZE, "%u\n", (u32)(deve->write_bytes >> 20)); - spin_unlock_irq(&nacl->device_list_lock); + ret = snprintf(page, PAGE_SIZE, "%u\n", + (u32)(atomic_long_read(&deve->write_bytes) >> 20)); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(write_mbytes); @@ -1332,15 +1335,15 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_hs_num_cmds( struct se_dev_entry *deve; ssize_t ret; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[lacl->mapped_lun]; - if (!deve->se_lun || !deve->se_lun_acl) { - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, lacl->mapped_lun); + if (!deve) { + rcu_read_unlock(); return -ENODEV; } /* FIXME: scsiAuthIntrHSOutCommands */ ret = snprintf(page, PAGE_SIZE, "%u\n", 0); - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(hs_num_cmds); @@ -1354,16 +1357,16 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_creation_time( struct se_dev_entry *deve; ssize_t ret; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[lacl->mapped_lun]; - if (!deve->se_lun || !deve->se_lun_acl) { - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, lacl->mapped_lun); + if (!deve) { + rcu_read_unlock(); return -ENODEV; } /* scsiAuthIntrLastCreation */ ret = snprintf(page, PAGE_SIZE, "%u\n", (u32)(((u32)deve->creation_time - INITIAL_JIFFIES) * 100 / HZ)); - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(creation_time); @@ -1377,15 +1380,15 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_row_status( struct se_dev_entry *deve; ssize_t ret; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[lacl->mapped_lun]; - if (!deve->se_lun || !deve->se_lun_acl) { - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, lacl->mapped_lun); + if (!deve) { + rcu_read_unlock(); return -ENODEV; } /* FIXME: scsiAuthIntrRowStatus */ ret = snprintf(page, PAGE_SIZE, "Ready\n"); - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(row_status); @@ -1450,17 +1453,17 @@ static ssize_t target_stat_scsi_att_intr_port_show_attr_inst( struct se_portal_group *tpg; ssize_t ret; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[lacl->mapped_lun]; - if (!deve->se_lun || !deve->se_lun_acl) { - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, lacl->mapped_lun); + if (!deve) { + rcu_read_unlock(); return -ENODEV; } tpg = nacl->se_tpg; /* scsiInstIndex */ ret = snprintf(page, PAGE_SIZE, "%u\n", tpg->se_tpg_tfo->tpg_get_inst_index(tpg)); - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(inst); @@ -1475,16 +1478,16 @@ static ssize_t target_stat_scsi_att_intr_port_show_attr_dev( struct se_lun *lun; ssize_t ret; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[lacl->mapped_lun]; - if (!deve->se_lun || !deve->se_lun_acl) { - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, lacl->mapped_lun); + if (!deve) { + rcu_read_unlock(); return -ENODEV; } - lun = deve->se_lun; + lun = rcu_dereference(deve->se_lun); /* scsiDeviceIndex */ - ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_se_dev->dev_index); - spin_unlock_irq(&nacl->device_list_lock); + ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_index); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(dev); @@ -1499,16 +1502,16 @@ static ssize_t target_stat_scsi_att_intr_port_show_attr_port( struct se_portal_group *tpg; ssize_t ret; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[lacl->mapped_lun]; - if (!deve->se_lun || !deve->se_lun_acl) { - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, lacl->mapped_lun); + if (!deve) { + rcu_read_unlock(); return -ENODEV; } tpg = nacl->se_tpg; /* scsiPortIndex */ ret = snprintf(page, PAGE_SIZE, "%u\n", tpg->se_tpg_tfo->tpg_get_tag(tpg)); - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(port); @@ -1548,15 +1551,15 @@ static ssize_t target_stat_scsi_att_intr_port_show_attr_port_auth_indx( struct se_dev_entry *deve; ssize_t ret; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[lacl->mapped_lun]; - if (!deve->se_lun || !deve->se_lun_acl) { - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, lacl->mapped_lun); + if (!deve) { + rcu_read_unlock(); return -ENODEV; } /* scsiAttIntrPortAuthIntrIdx */ ret = snprintf(page, PAGE_SIZE, "%u\n", nacl->acl_index); - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(port_auth_indx); diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index c0c1f67facb5..0519923ef930 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -47,42 +47,6 @@ extern struct se_device *g_lun0_dev; static DEFINE_SPINLOCK(tpg_lock); static LIST_HEAD(tpg_list); -/* core_clear_initiator_node_from_tpg(): - * - * - */ -static void core_clear_initiator_node_from_tpg( - struct se_node_acl *nacl, - struct se_portal_group *tpg) -{ - int i; - struct se_dev_entry *deve; - struct se_lun *lun; - - spin_lock_irq(&nacl->device_list_lock); - for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { - deve = nacl->device_list[i]; - - if (!(deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS)) - continue; - - if (!deve->se_lun) { - pr_err("%s device entries device pointer is" - " NULL, but Initiator has access.\n", - tpg->se_tpg_tfo->get_fabric_name()); - continue; - } - - lun = deve->se_lun; - spin_unlock_irq(&nacl->device_list_lock); - core_disable_device_list_for_node(lun, NULL, deve->mapped_lun, - TRANSPORT_LUNFLAGS_NO_ACCESS, nacl, tpg); - - spin_lock_irq(&nacl->device_list_lock); - } - spin_unlock_irq(&nacl->device_list_lock); -} - /* __core_tpg_get_initiator_node_acl(): * * spin_lock_bh(&tpg->acl_node_lock); must be held when calling @@ -225,35 +189,6 @@ static void *array_zalloc(int n, size_t size, gfp_t flags) return a; } -/* core_create_device_list_for_node(): - * - * - */ -static int core_create_device_list_for_node(struct se_node_acl *nacl) -{ - struct se_dev_entry *deve; - int i; - - nacl->device_list = array_zalloc(TRANSPORT_MAX_LUNS_PER_TPG, - sizeof(struct se_dev_entry), GFP_KERNEL); - if (!nacl->device_list) { - pr_err("Unable to allocate memory for" - " struct se_node_acl->device_list\n"); - return -ENOMEM; - } - for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { - deve = nacl->device_list[i]; - - atomic_set(&deve->ua_count, 0); - atomic_set(&deve->pr_ref_count, 0); - spin_lock_init(&deve->ua_lock); - INIT_LIST_HEAD(&deve->alua_port_list); - INIT_LIST_HEAD(&deve->ua_list); - } - - return 0; -} - static struct se_node_acl *target_alloc_node_acl(struct se_portal_group *tpg, const unsigned char *initiatorname) { @@ -266,10 +201,11 @@ static struct se_node_acl *target_alloc_node_acl(struct se_portal_group *tpg, INIT_LIST_HEAD(&acl->acl_list); INIT_LIST_HEAD(&acl->acl_sess_list); + INIT_HLIST_HEAD(&acl->lun_entry_hlist); kref_init(&acl->acl_kref); init_completion(&acl->acl_free_comp); - spin_lock_init(&acl->device_list_lock); spin_lock_init(&acl->nacl_sess_lock); + mutex_init(&acl->lun_entry_mutex); atomic_set(&acl->acl_pr_ref_count, 0); if (tpg->se_tpg_tfo->tpg_get_default_depth) acl->queue_depth = tpg->se_tpg_tfo->tpg_get_default_depth(tpg); @@ -281,15 +217,11 @@ static struct se_node_acl *target_alloc_node_acl(struct se_portal_group *tpg, tpg->se_tpg_tfo->set_default_node_attributes(acl); - if (core_create_device_list_for_node(acl) < 0) - goto out_free_acl; if (core_set_queue_depth_for_node(tpg, acl) < 0) - goto out_free_device_list; + goto out_free_acl; return acl; -out_free_device_list: - core_free_device_list_for_node(acl, tpg); out_free_acl: kfree(acl); return NULL; @@ -454,7 +386,6 @@ void core_tpg_del_initiator_node_acl(struct se_node_acl *acl) wait_for_completion(&acl->acl_free_comp); core_tpg_wait_for_nacl_pr_ref(acl); - core_clear_initiator_node_from_tpg(acl, tpg); core_free_device_list_for_node(acl, tpg); pr_debug("%s_TPG[%hu] - Deleted ACL with TCQ Depth: %d for %s" diff --git a/drivers/target/target_core_ua.c b/drivers/target/target_core_ua.c index a0bf0d1a3df7..6c9616d212b1 100644 --- a/drivers/target/target_core_ua.c +++ b/drivers/target/target_core_ua.c @@ -50,9 +50,17 @@ target_scsi3_ua_check(struct se_cmd *cmd) if (!nacl) return 0; - deve = nacl->device_list[cmd->orig_fe_lun]; - if (!atomic_read(&deve->ua_count)) + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, cmd->orig_fe_lun); + if (!deve) { + rcu_read_unlock(); return 0; + } + if (!atomic_read(&deve->ua_count)) { + rcu_read_unlock(); + return 0; + } + rcu_read_unlock(); /* * From sam4r14, section 5.14 Unit attention condition: * @@ -103,9 +111,12 @@ int core_scsi3_ua_allocate( ua->ua_asc = asc; ua->ua_ascq = ascq; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[unpacked_lun]; - + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, unpacked_lun); + if (!deve) { + rcu_read_unlock(); + return -EINVAL; + } spin_lock(&deve->ua_lock); list_for_each_entry_safe(ua_p, ua_tmp, &deve->ua_list, ua_nacl_list) { /* @@ -113,7 +124,7 @@ int core_scsi3_ua_allocate( */ if ((ua_p->ua_asc == asc) && (ua_p->ua_ascq == ascq)) { spin_unlock(&deve->ua_lock); - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_unlock(); kmem_cache_free(se_ua_cache, ua); return 0; } @@ -158,14 +169,13 @@ int core_scsi3_ua_allocate( list_add_tail(&ua->ua_nacl_list, &deve->ua_list); spin_unlock(&deve->ua_lock); - spin_unlock_irq(&nacl->device_list_lock); atomic_inc_mb(&deve->ua_count); + rcu_read_unlock(); return 0; } list_add_tail(&ua->ua_nacl_list, &deve->ua_list); spin_unlock(&deve->ua_lock); - spin_unlock_irq(&nacl->device_list_lock); pr_debug("[%s]: Allocated UNIT ATTENTION, mapped LUN: %u, ASC:" " 0x%02x, ASCQ: 0x%02x\n", @@ -173,6 +183,7 @@ int core_scsi3_ua_allocate( asc, ascq); atomic_inc_mb(&deve->ua_count); + rcu_read_unlock(); return 0; } @@ -210,10 +221,14 @@ void core_scsi3_ua_for_check_condition( if (!nacl) return; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[cmd->orig_fe_lun]; + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, cmd->orig_fe_lun); + if (!deve) { + rcu_read_unlock(); + return; + } if (!atomic_read(&deve->ua_count)) { - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_unlock(); return; } /* @@ -249,7 +264,7 @@ void core_scsi3_ua_for_check_condition( atomic_dec_mb(&deve->ua_count); } spin_unlock(&deve->ua_lock); - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_unlock(); pr_debug("[%s]: %s UNIT ATTENTION condition with" " INTLCK_CTRL: %d, mapped LUN: %u, got CDB: 0x%02x" @@ -278,10 +293,14 @@ int core_scsi3_ua_clear_for_request_sense( if (!nacl) return -EINVAL; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[cmd->orig_fe_lun]; + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, cmd->orig_fe_lun); + if (!deve) { + rcu_read_unlock(); + return -EINVAL; + } if (!atomic_read(&deve->ua_count)) { - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_unlock(); return -EPERM; } /* @@ -307,7 +326,7 @@ int core_scsi3_ua_clear_for_request_sense( atomic_dec_mb(&deve->ua_count); } spin_unlock(&deve->ua_lock); - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_unlock(); pr_debug("[%s]: Released UNIT ATTENTION condition, mapped" " LUN: %u, got REQUEST_SENSE reported ASC: 0x%02x," diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index 47fafec556f8..80d9e486e33e 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -101,7 +101,7 @@ int target_alloc_sgl(struct scatterlist **, unsigned int *, u32, bool); sense_reason_t transport_generic_map_mem_to_cmd(struct se_cmd *, struct scatterlist *, u32, struct scatterlist *, u32); -void array_free(void *array, int n); +bool target_lun_is_rdonly(struct se_cmd *); /* From target_core_configfs.c to setup default backend config_item_types */ void target_core_setup_sub_cits(struct se_subsystem_api *); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 042a73464966..b518523cba7b 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -160,10 +160,8 @@ enum se_cmd_flags_table { /* struct se_dev_entry->lun_flags and struct se_lun->lun_access */ enum transport_lunflags_table { - TRANSPORT_LUNFLAGS_NO_ACCESS = 0x00, - TRANSPORT_LUNFLAGS_INITIATOR_ACCESS = 0x01, - TRANSPORT_LUNFLAGS_READ_ONLY = 0x02, - TRANSPORT_LUNFLAGS_READ_WRITE = 0x04, + TRANSPORT_LUNFLAGS_READ_ONLY = 0x01, + TRANSPORT_LUNFLAGS_READ_WRITE = 0x02, }; /* @@ -584,10 +582,10 @@ struct se_node_acl { char acl_tag[MAX_ACL_TAG_SIZE]; /* Used for PR SPEC_I_PT=1 and REGISTER_AND_MOVE */ atomic_t acl_pr_ref_count; - struct se_dev_entry **device_list; + struct hlist_head lun_entry_hlist; struct se_session *nacl_sess; struct se_portal_group *se_tpg; - spinlock_t device_list_lock; + struct mutex lun_entry_mutex; spinlock_t nacl_sess_lock; struct config_group acl_group; struct config_group acl_attrib_group; @@ -644,20 +642,23 @@ struct se_dev_entry { /* See transport_lunflags_table */ u32 lun_flags; u32 mapped_lun; - u32 total_cmds; u64 pr_res_key; u64 creation_time; u32 attach_count; - u64 read_bytes; - u64 write_bytes; + atomic_long_t total_cmds; + atomic_long_t read_bytes; + atomic_long_t write_bytes; atomic_t ua_count; /* Used for PR SPEC_I_PT=1 and REGISTER_AND_MOVE */ - atomic_t pr_ref_count; - struct se_lun_acl *se_lun_acl; + struct kref pr_kref; + struct completion pr_comp; + struct se_lun_acl __rcu *se_lun_acl; spinlock_t ua_lock; - struct se_lun *se_lun; + struct se_lun __rcu *se_lun; struct list_head alua_port_list; struct list_head ua_list; + struct hlist_node link; + struct rcu_head rcu_head; }; struct se_dev_attrib { @@ -703,6 +704,7 @@ struct se_port_stat_grps { }; struct se_lun { + u16 lun_rtpi; #define SE_LUN_LINK_MAGIC 0xffff7771 u32 lun_link_magic; /* See transport_lun_status_table */ @@ -710,6 +712,7 @@ struct se_lun { u32 lun_access; u32 lun_flags; u32 unpacked_lun; + u32 lun_index; atomic_t lun_acl_count; spinlock_t lun_acl_lock; spinlock_t lun_sep_lock; -- cgit v1.2.3-70-g09d2 From 80bfdfa92481d431b199eff72788588d13a3988f Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Wed, 25 Mar 2015 01:02:57 -0700 Subject: target/pr: Use atomic bitop for se_dev_entry->deve_flags reservation check This patch converts the core_scsi3_pr_seq_non_holder() check for non reservation holding registrations to use an atomic bitop in ->deve_flags to determine if a registration is currently active. It also includes associated a set_bit() in __core_scsi3_add_registration() and clear_bit() in __core_scsi3_free_registration(), if se_dev_entry still exists, and has not already been released via se_dev_entry shutdown path in core_disable_device_list_for_node(). Also, clear_bit in core_disable_device_list_for_node as well to ensure the read-critical path in core_scsi3_pr_seq_non_holder() picks up the new state, preceeding the final kfree_rcu() call. Reported-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Cc: Sagi Grimberg Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_device.c | 1 + drivers/target/target_core_pr.c | 58 +++++++++++++++++++++++++------------ include/target/target_core_base.h | 3 +- 3 files changed, 42 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index e44e6bd66659..97792cc81fe4 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -413,6 +413,7 @@ void core_disable_device_list_for_node( core_scsi3_ua_release_all(orig); hlist_del_rcu(&orig->link); + clear_bit(DEF_PR_REG_ACTIVE, &orig->deve_flags); rcu_assign_pointer(orig->se_lun, NULL); rcu_assign_pointer(orig->se_lun_acl, NULL); orig->lun_flags = 0; diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 909573a682d5..66e686bdf894 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -327,9 +327,13 @@ static int core_scsi3_pr_seq_non_holder( int we = 0; /* Write Exclusive */ int legacy = 0; /* Act like a legacy device and return * RESERVATION CONFLICT on some CDBs */ + bool registered = false; rcu_read_lock(); se_deve = target_nacl_find_deve(nacl, cmd->orig_fe_lun); + if (se_deve) + registered = test_bit(DEF_PR_REG_ACTIVE, &se_deve->deve_flags); + rcu_read_unlock(); /* * Determine if the registration should be ignored due to * non-matching ISIDs in target_scsi3_pr_reservation_check(). @@ -346,7 +350,7 @@ static int core_scsi3_pr_seq_non_holder( * Some commands are only allowed for the persistent reservation * holder. */ - if ((se_deve->def_pr_registered) && !(ignore_reg)) + if ((registered) && !(ignore_reg)) registered_nexus = 1; break; case PR_TYPE_WRITE_EXCLUSIVE_REGONLY: @@ -356,7 +360,7 @@ static int core_scsi3_pr_seq_non_holder( * Some commands are only allowed for registered I_T Nexuses. */ reg_only = 1; - if ((se_deve->def_pr_registered) && !(ignore_reg)) + if ((registered) && !(ignore_reg)) registered_nexus = 1; break; case PR_TYPE_WRITE_EXCLUSIVE_ALLREG: @@ -366,14 +370,12 @@ static int core_scsi3_pr_seq_non_holder( * Each registered I_T Nexus is a reservation holder. */ all_reg = 1; - if ((se_deve->def_pr_registered) && !(ignore_reg)) + if ((registered) && !(ignore_reg)) registered_nexus = 1; break; default: - rcu_read_unlock(); return -EINVAL; } - rcu_read_unlock(); /* * Referenced from spc4r17 table 45 for *NON* PR holder access */ @@ -1009,10 +1011,6 @@ static void __core_scsi3_dump_registration( pr_reg->pr_reg_aptpl); } -/* - * this function can be called with struct se_device->dev_reservation_lock - * when register_move = 1 - */ static void __core_scsi3_add_registration( struct se_device *dev, struct se_node_acl *nacl, @@ -1023,6 +1021,7 @@ static void __core_scsi3_add_registration( const struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo; struct t10_pr_registration *pr_reg_tmp, *pr_reg_tmp_safe; struct t10_reservation *pr_tmpl = &dev->t10_pr; + struct se_dev_entry *deve; /* * Increment PRgeneration counter for struct se_device upon a successful @@ -1039,10 +1038,16 @@ static void __core_scsi3_add_registration( spin_lock(&pr_tmpl->registration_lock); list_add_tail(&pr_reg->pr_reg_list, &pr_tmpl->registration_list); - pr_reg->pr_reg_deve->def_pr_registered = 1; __core_scsi3_dump_registration(tfo, dev, nacl, pr_reg, register_type); spin_unlock(&pr_tmpl->registration_lock); + + rcu_read_lock(); + deve = pr_reg->pr_reg_deve; + if (deve) + set_bit(DEF_PR_REG_ACTIVE, &deve->deve_flags); + rcu_read_unlock(); + /* * Skip extra processing for ALL_TG_PT=0 or REGISTER_AND_MOVE. */ @@ -1054,6 +1059,8 @@ static void __core_scsi3_add_registration( */ list_for_each_entry_safe(pr_reg_tmp, pr_reg_tmp_safe, &pr_reg->pr_reg_atp_list, pr_reg_atp_mem_list) { + struct se_node_acl *nacl_tmp = pr_reg_tmp->pr_reg_nacl; + list_del(&pr_reg_tmp->pr_reg_atp_mem_list); pr_reg_tmp->pr_res_generation = core_scsi3_pr_generation(dev); @@ -1061,12 +1068,17 @@ static void __core_scsi3_add_registration( spin_lock(&pr_tmpl->registration_lock); list_add_tail(&pr_reg_tmp->pr_reg_list, &pr_tmpl->registration_list); - pr_reg_tmp->pr_reg_deve->def_pr_registered = 1; - __core_scsi3_dump_registration(tfo, dev, - pr_reg_tmp->pr_reg_nacl, pr_reg_tmp, - register_type); + __core_scsi3_dump_registration(tfo, dev, nacl_tmp, pr_reg_tmp, + register_type); spin_unlock(&pr_tmpl->registration_lock); + + rcu_read_lock(); + deve = pr_reg_tmp->pr_reg_deve; + if (deve) + set_bit(DEF_PR_REG_ACTIVE, &deve->deve_flags); + rcu_read_unlock(); + /* * Drop configfs group dependency reference from * __core_scsi3_alloc_registration() @@ -1242,13 +1254,13 @@ static void __core_scsi3_free_registration( const struct target_core_fabric_ops *tfo = pr_reg->pr_reg_nacl->se_tpg->se_tpg_tfo; struct t10_reservation *pr_tmpl = &dev->t10_pr; + struct se_node_acl *nacl = pr_reg->pr_reg_nacl; + struct se_dev_entry *deve; char i_buf[PR_REG_ISID_ID_LEN]; memset(i_buf, 0, PR_REG_ISID_ID_LEN); core_pr_dump_initiator_port(pr_reg, i_buf, PR_REG_ISID_ID_LEN); - pr_reg->pr_reg_deve->def_pr_registered = 0; - pr_reg->pr_reg_deve->pr_res_key = 0; if (!list_empty(&pr_reg->pr_reg_list)) list_del(&pr_reg->pr_reg_list); /* @@ -1257,6 +1269,8 @@ static void __core_scsi3_free_registration( */ if (dec_holders) core_scsi3_put_pr_reg(pr_reg); + + spin_unlock(&pr_tmpl->registration_lock); /* * Wait until all reference from any other I_T nexuses for this * *pr_reg have been released. Because list_del() is called above, @@ -1264,13 +1278,18 @@ static void __core_scsi3_free_registration( * count back to zero, and we release *pr_reg. */ while (atomic_read(&pr_reg->pr_res_holders) != 0) { - spin_unlock(&pr_tmpl->registration_lock); pr_debug("SPC-3 PR [%s] waiting for pr_res_holders\n", tfo->get_fabric_name()); cpu_relax(); - spin_lock(&pr_tmpl->registration_lock); } + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, pr_reg->pr_res_mapped_lun); + if (deve) + clear_bit(DEF_PR_REG_ACTIVE, &deve->deve_flags); + rcu_read_unlock(); + + spin_lock(&pr_tmpl->registration_lock); pr_debug("SPC-3 PR [%s] Service Action: UNREGISTER Initiator" " Node: %s%s\n", tfo->get_fabric_name(), pr_reg->pr_reg_nacl->initiatorname, @@ -3421,13 +3440,14 @@ after_iport_check: dest_pr_reg = __core_scsi3_locate_pr_reg(dev, dest_node_acl, iport_ptr); if (!dest_pr_reg) { + spin_unlock(&dev->dev_reservation_lock); if (core_scsi3_alloc_registration(cmd->se_dev, dest_node_acl, dest_se_deve, iport_ptr, sa_res_key, 0, aptpl, 2, 1)) { - spin_unlock(&dev->dev_reservation_lock); ret = TCM_INVALID_PARAMETER_LIST; goto out; } + spin_lock(&dev->dev_reservation_lock); dest_pr_reg = __core_scsi3_locate_pr_reg(dev, dest_node_acl, iport_ptr); new_reg = 1; diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index b518523cba7b..508528a5e927 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -638,7 +638,6 @@ struct se_lun_acl { }; struct se_dev_entry { - bool def_pr_registered; /* See transport_lunflags_table */ u32 lun_flags; u32 mapped_lun; @@ -655,6 +654,8 @@ struct se_dev_entry { struct se_lun_acl __rcu *se_lun_acl; spinlock_t ua_lock; struct se_lun __rcu *se_lun; +#define DEF_PR_REG_ACTIVE 1 + unsigned long deve_flags; struct list_head alua_port_list; struct list_head ua_list; struct hlist_node link; -- cgit v1.2.3-70-g09d2 From 79dc9c9e865a7f8c14737453f112ced25deafdef Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Fri, 27 Mar 2015 04:51:03 +0000 Subject: target/pr: Change alloc_registration to avoid pr_reg_tg_pt_lun This patch changes __core_scsi3_do_alloc_registration() code to drop pr_reg->pr_reg_tg_pt_lun pointer usage in favor of a new pr_reg RPTI + existing pr_reg->pr_aptpl_target_lun used by APTPL metadata logic. It also includes changes to REGISTER, REGISTER_AND_MOVE and APTPL feature bit codepaths to use rcu_dereference_check() with the expected non-zero se_dev_entry->pr_kref reference held. Reviewed-by: Hannes Reinecke Cc: Christoph Hellwig Cc: Sagi Grimberg Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_configfs.c | 6 +- drivers/target/target_core_pr.c | 131 ++++++++++++++++++---------------- include/target/target_core_base.h | 4 +- 3 files changed, 72 insertions(+), 69 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 798386a1b6e7..4a31d4765390 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -817,7 +817,6 @@ static ssize_t target_core_dev_pr_show_attr_res_pr_holder_tg_port( struct se_device *dev, char *page) { struct se_node_acl *se_nacl; - struct se_lun *lun; struct se_portal_group *se_tpg; struct t10_pr_registration *pr_reg; const struct target_core_fabric_ops *tfo; @@ -832,7 +831,6 @@ static ssize_t target_core_dev_pr_show_attr_res_pr_holder_tg_port( se_nacl = pr_reg->pr_reg_nacl; se_tpg = se_nacl->se_tpg; - lun = pr_reg->pr_reg_tg_pt_lun; tfo = se_tpg->se_tpg_tfo; len += sprintf(page+len, "SPC-3 Reservation: %s" @@ -840,9 +838,9 @@ static ssize_t target_core_dev_pr_show_attr_res_pr_holder_tg_port( tfo->tpg_get_wwn(se_tpg)); len += sprintf(page+len, "SPC-3 Reservation: Relative Port" " Identifier Tag: %hu %s Portal Group Tag: %hu" - " %s Logical Unit: %u\n", lun->lun_sep->sep_rtpi, + " %s Logical Unit: %u\n", pr_reg->tg_pt_sep_rtpi, tfo->get_fabric_name(), tfo->tpg_get_tag(se_tpg), - tfo->get_fabric_name(), lun->unpacked_lun); + tfo->get_fabric_name(), pr_reg->pr_aptpl_target_lun); out_unlock: spin_unlock(&dev->dev_reservation_lock); diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 66e686bdf894..48ed5d2bf5fe 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -44,11 +44,10 @@ * Used for Specify Initiator Ports Capable Bit (SPEC_I_PT) */ struct pr_transport_id_holder { - int dest_local_nexus; struct t10_pr_registration *dest_pr_reg; struct se_portal_group *dest_tpg; struct se_node_acl *dest_node_acl; - struct se_dev_entry __rcu *dest_se_deve; + struct se_dev_entry *dest_se_deve; struct list_head dest_list; }; @@ -625,7 +624,9 @@ static u32 core_scsi3_pr_generation(struct se_device *dev) static struct t10_pr_registration *__core_scsi3_do_alloc_registration( struct se_device *dev, struct se_node_acl *nacl, + struct se_lun *lun, struct se_dev_entry *deve, + u32 mapped_lun, unsigned char *isid, u64 sa_res_key, int all_tg_pt, @@ -647,12 +648,12 @@ static struct t10_pr_registration *__core_scsi3_do_alloc_registration( atomic_set(&pr_reg->pr_res_holders, 0); pr_reg->pr_reg_nacl = nacl; pr_reg->pr_reg_deve = deve; - pr_reg->pr_res_mapped_lun = deve->mapped_lun; - pr_reg->pr_aptpl_target_lun = deve->se_lun->unpacked_lun; + pr_reg->pr_res_mapped_lun = mapped_lun; + pr_reg->pr_aptpl_target_lun = lun->unpacked_lun; + pr_reg->tg_pt_sep_rtpi = lun->lun_sep->sep_rtpi; pr_reg->pr_res_key = sa_res_key; pr_reg->pr_reg_all_tg_pt = all_tg_pt; pr_reg->pr_reg_aptpl = aptpl; - pr_reg->pr_reg_tg_pt_lun = deve->se_lun; /* * If an ISID value for this SCSI Initiator Port exists, * save it to the registration now. @@ -676,7 +677,9 @@ static void core_scsi3_lunacl_undepend_item(struct se_dev_entry *); static struct t10_pr_registration *__core_scsi3_alloc_registration( struct se_device *dev, struct se_node_acl *nacl, + struct se_lun *lun, struct se_dev_entry *deve, + u32 mapped_lun, unsigned char *isid, u64 sa_res_key, int all_tg_pt, @@ -684,6 +687,8 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( { struct se_dev_entry *deve_tmp; struct se_node_acl *nacl_tmp; + struct se_lun_acl *lacl_tmp; + struct se_lun *lun_tmp; struct se_port *port, *port_tmp; const struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo; struct t10_pr_registration *pr_reg, *pr_reg_atp, *pr_reg_tmp, *pr_reg_tmp_safe; @@ -692,8 +697,9 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( * Create a registration for the I_T Nexus upon which the * PROUT REGISTER was received. */ - pr_reg = __core_scsi3_do_alloc_registration(dev, nacl, deve, isid, - sa_res_key, all_tg_pt, aptpl); + pr_reg = __core_scsi3_do_alloc_registration(dev, nacl, lun, deve, mapped_lun, + isid, sa_res_key, all_tg_pt, + aptpl); if (!pr_reg) return NULL; /* @@ -721,7 +727,9 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( if (!deve_tmp->se_lun_acl) continue; - nacl_tmp = deve_tmp->se_lun_acl->se_lun_nacl; + lacl_tmp = rcu_dereference_check(deve_tmp->se_lun_acl, + lockdep_is_held(&port->sep_alua_lock)); + nacl_tmp = lacl_tmp->se_lun_nacl; /* * Skip the matching struct se_node_acl that is allocated * above.. @@ -764,8 +772,12 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( * the original *pr_reg is processed in * __core_scsi3_add_registration() */ + lun_tmp = rcu_dereference_check(deve_tmp->se_lun, + atomic_read(&deve_tmp->pr_kref.refcount) != 0); + pr_reg_atp = __core_scsi3_do_alloc_registration(dev, - nacl_tmp, deve_tmp, NULL, + nacl_tmp, lun_tmp, deve_tmp, + deve_tmp->mapped_lun, NULL, sa_res_key, all_tg_pt, aptpl); if (!pr_reg_atp) { atomic_dec_mb(&port->sep_tg_pt_ref_cnt); @@ -835,7 +847,6 @@ int core_scsi3_alloc_aptpl_registration( pr_reg->pr_res_key = sa_res_key; pr_reg->pr_reg_all_tg_pt = all_tg_pt; pr_reg->pr_reg_aptpl = 1; - pr_reg->pr_reg_tg_pt_lun = NULL; pr_reg->pr_res_scope = 0; /* Always LUN_SCOPE */ pr_reg->pr_res_type = type; /* @@ -935,7 +946,7 @@ static int __core_scsi3_check_aptpl_registration( (pr_reg->pr_aptpl_target_lun == target_lun)) { pr_reg->pr_reg_nacl = nacl; - pr_reg->pr_reg_tg_pt_lun = lun; + pr_reg->tg_pt_sep_rtpi = lun->lun_sep->sep_rtpi; list_del(&pr_reg->pr_reg_aptpl_list); spin_unlock(&pr_tmpl->aptpl_reg_lock); @@ -1090,7 +1101,9 @@ static void __core_scsi3_add_registration( static int core_scsi3_alloc_registration( struct se_device *dev, struct se_node_acl *nacl, + struct se_lun *lun, struct se_dev_entry *deve, + u32 mapped_lun, unsigned char *isid, u64 sa_res_key, int all_tg_pt, @@ -1100,8 +1113,9 @@ static int core_scsi3_alloc_registration( { struct t10_pr_registration *pr_reg; - pr_reg = __core_scsi3_alloc_registration(dev, nacl, deve, isid, - sa_res_key, all_tg_pt, aptpl); + pr_reg = __core_scsi3_alloc_registration(dev, nacl, lun, deve, mapped_lun, + isid, sa_res_key, all_tg_pt, + aptpl); if (!pr_reg) return -EPERM; @@ -1411,12 +1425,14 @@ static void core_scsi3_nodeacl_undepend_item(struct se_node_acl *nacl) static int core_scsi3_lunacl_depend_item(struct se_dev_entry *se_deve) { - struct se_lun_acl *lun_acl = se_deve->se_lun_acl; + struct se_lun_acl *lun_acl; struct se_node_acl *nacl; struct se_portal_group *tpg; /* * For nacl->dynamic_node_acl=1 */ + lun_acl = rcu_dereference_check(se_deve->se_lun_acl, + atomic_read(&se_deve->pr_kref.refcount) != 0); if (!lun_acl) return 0; @@ -1434,7 +1450,8 @@ static void core_scsi3_lunacl_undepend_item(struct se_dev_entry *se_deve) /* * For nacl->dynamic_node_acl=1 */ - lun_acl = se_deve->se_lun_acl; + lun_acl = rcu_dereference_check(se_deve->se_lun_acl, + atomic_read(&se_deve->pr_kref.refcount) != 0); if (!lun_acl) { kref_put(&se_deve->pr_kref, target_pr_kref_release); return; @@ -1450,7 +1467,6 @@ static sense_reason_t core_scsi3_decode_spec_i_port( struct se_cmd *cmd, struct se_portal_group *tpg, - struct se_dev_entry *local_se_deve, unsigned char *l_isid, u64 sa_res_key, int all_tg_pt, @@ -1461,7 +1477,7 @@ core_scsi3_decode_spec_i_port( struct se_portal_group *dest_tpg = NULL, *tmp_tpg; struct se_session *se_sess = cmd->se_sess; struct se_node_acl *dest_node_acl = NULL; - struct se_dev_entry __rcu *dest_se_deve = NULL; + struct se_dev_entry *dest_se_deve = NULL; struct t10_pr_registration *dest_pr_reg, *local_pr_reg, *pr_reg_e; struct t10_pr_registration *pr_reg_tmp, *pr_reg_tmp_safe; LIST_HEAD(tid_dest_list); @@ -1471,14 +1487,12 @@ core_scsi3_decode_spec_i_port( char *iport_ptr = NULL, i_buf[PR_REG_ISID_ID_LEN]; sense_reason_t ret; u32 tpdl, tid_len = 0; - int dest_local_nexus; u32 dest_rtpi = 0; /* * Allocate a struct pr_transport_id_holder and setup the - * local_node_acl and local_se_deve pointers and add to - * struct list_head tid_dest_list for add registration - * processing in the loop of tid_dest_list below. + * local_node_acl pointer and add to struct list_head tid_dest_list + * for add registration processing in the loop of tid_dest_list below. */ tidh_new = kzalloc(sizeof(struct pr_transport_id_holder), GFP_KERNEL); if (!tidh_new) { @@ -1490,20 +1504,20 @@ core_scsi3_decode_spec_i_port( tidh_new->dest_node_acl = se_sess->se_node_acl; local_pr_reg = __core_scsi3_alloc_registration(cmd->se_dev, - se_sess->se_node_acl, local_se_deve, l_isid, + se_sess->se_node_acl, cmd->se_lun, + NULL, cmd->orig_fe_lun, l_isid, sa_res_key, all_tg_pt, aptpl); if (!local_pr_reg) { kfree(tidh_new); return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } - rcu_assign_pointer(tidh_new->dest_se_deve, local_se_deve); tidh_new->dest_pr_reg = local_pr_reg; /* * The local I_T nexus does not hold any configfs dependances, - * so we set tid_h->dest_local_nexus=1 to prevent the + * so we set tidh_new->dest_se_deve to NULL to prevent the * configfs_undepend_item() calls in the tid_dest_list loops below. */ - tidh_new->dest_local_nexus = 1; + tidh_new->dest_se_deve = NULL; list_add_tail(&tidh_new->dest_list, &tid_dest_list); if (cmd->data_length < 28) { @@ -1544,6 +1558,8 @@ core_scsi3_decode_spec_i_port( ptr = &buf[28]; while (tpdl > 0) { + struct se_lun *dest_lun; + proto_ident = (ptr[0] & 0x0f); dest_tpg = NULL; @@ -1720,9 +1736,13 @@ core_scsi3_decode_spec_i_port( * and then call __core_scsi3_add_registration() in the * 2nd loop which will never fail. */ + dest_lun = rcu_dereference_check(dest_se_deve->se_lun, + atomic_read(&dest_se_deve->pr_kref.refcount) != 0); + dest_pr_reg = __core_scsi3_alloc_registration(cmd->se_dev, - dest_node_acl, dest_se_deve, iport_ptr, - sa_res_key, all_tg_pt, aptpl); + dest_node_acl, dest_lun, dest_se_deve, + dest_se_deve->mapped_lun, iport_ptr, + sa_res_key, all_tg_pt, aptpl); if (!dest_pr_reg) { core_scsi3_lunacl_undepend_item(dest_se_deve); core_scsi3_nodeacl_undepend_item(dest_node_acl); @@ -1760,7 +1780,6 @@ core_scsi3_decode_spec_i_port( dest_node_acl = tidh->dest_node_acl; dest_se_deve = tidh->dest_se_deve; dest_pr_reg = tidh->dest_pr_reg; - dest_local_nexus = tidh->dest_local_nexus; list_del(&tidh->dest_list); kfree(tidh); @@ -1774,9 +1793,10 @@ core_scsi3_decode_spec_i_port( pr_debug("SPC-3 PR [%s] SPEC_I_PT: Successfully" " registered Transport ID for Node: %s%s Mapped LUN:" " %u\n", dest_tpg->se_tpg_tfo->get_fabric_name(), - dest_node_acl->initiatorname, i_buf, dest_se_deve->mapped_lun); + dest_node_acl->initiatorname, i_buf, (dest_se_deve) ? + dest_se_deve->mapped_lun : 0); - if (dest_local_nexus) + if (!dest_se_deve) continue; core_scsi3_lunacl_undepend_item(dest_se_deve); @@ -1797,7 +1817,6 @@ out: dest_node_acl = tidh->dest_node_acl; dest_se_deve = tidh->dest_se_deve; dest_pr_reg = tidh->dest_pr_reg; - dest_local_nexus = tidh->dest_local_nexus; list_del(&tidh->dest_list); kfree(tidh); @@ -1815,7 +1834,7 @@ out: kmem_cache_free(t10_pr_reg_cache, dest_pr_reg); - if (dest_local_nexus) + if (!dest_se_deve) continue; core_scsi3_lunacl_undepend_item(dest_se_deve); @@ -1830,7 +1849,6 @@ static int core_scsi3_update_aptpl_buf( unsigned char *buf, u32 pr_aptpl_buf_len) { - struct se_lun *lun; struct se_portal_group *tpg; struct t10_pr_registration *pr_reg; unsigned char tmp[512], isid_buf[32]; @@ -1849,7 +1867,6 @@ static int core_scsi3_update_aptpl_buf( tmp[0] = '\0'; isid_buf[0] = '\0'; tpg = pr_reg->pr_reg_nacl->se_tpg; - lun = pr_reg->pr_reg_tg_pt_lun; /* * Write out any ISID value to APTPL metadata that was included * in the original registration. @@ -1901,7 +1918,8 @@ static int core_scsi3_update_aptpl_buf( " %d\n", tpg->se_tpg_tfo->get_fabric_name(), tpg->se_tpg_tfo->tpg_get_wwn(tpg), tpg->se_tpg_tfo->tpg_get_tag(tpg), - lun->lun_sep->sep_rtpi, lun->unpacked_lun, reg_count); + pr_reg->tg_pt_sep_rtpi, pr_reg->pr_aptpl_target_lun, + reg_count); if ((len + strlen(tmp) >= pr_aptpl_buf_len)) { pr_err("Unable to update renaming APTPL metadata," @@ -2011,9 +2029,7 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key, bool aptpl, bool all_tg_pt, bool spec_i_pt, enum register_type register_type) { struct se_session *se_sess = cmd->se_sess; - struct se_node_acl *nacl = se_sess->se_node_acl; struct se_device *dev = cmd->se_dev; - struct se_dev_entry *se_deve; struct se_lun *se_lun = cmd->se_lun; struct se_portal_group *se_tpg; struct t10_pr_registration *pr_reg, *pr_reg_p, *pr_reg_tmp; @@ -2028,14 +2044,6 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key, } se_tpg = se_sess->se_tpg; - rcu_read_lock(); - se_deve = target_nacl_find_deve(nacl, cmd->orig_fe_lun); - if (!se_deve) { - pr_err("Unable to locate se_deve for PRO-REGISTER\n"); - rcu_read_unlock(); - return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - } - if (se_tpg->se_tpg_tfo->sess_get_initiator_sid) { memset(&isid_buf[0], 0, PR_REG_ISID_LEN); se_tpg->se_tpg_tfo->sess_get_initiator_sid(se_sess, &isid_buf[0], @@ -2050,16 +2058,14 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key, if (res_key) { pr_warn("SPC-3 PR: Reservation Key non-zero" " for SA REGISTER, returning CONFLICT\n"); - rcu_read_unlock(); return TCM_RESERVATION_CONFLICT; } /* * Do nothing but return GOOD status. */ - if (!sa_res_key) { - rcu_read_unlock(); + if (!sa_res_key) return 0; - } + if (!spec_i_pt) { /* * Perform the Service Action REGISTER on the Initiator @@ -2067,12 +2073,12 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key, * Logical Unit of the SCSI device server. */ if (core_scsi3_alloc_registration(cmd->se_dev, - se_sess->se_node_acl, se_deve, isid_ptr, + se_sess->se_node_acl, cmd->se_lun, + NULL, cmd->orig_fe_lun, isid_ptr, sa_res_key, all_tg_pt, aptpl, register_type, 0)) { pr_err("Unable to allocate" " struct t10_pr_registration\n"); - rcu_read_unlock(); return TCM_INVALID_PARAMETER_LIST; } } else { @@ -2084,17 +2090,13 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key, * logic from of core_scsi3_alloc_registration() for * each TransportID provided SCSI Initiator Port/Device */ - ret = core_scsi3_decode_spec_i_port(cmd, se_tpg, se_deve, + ret = core_scsi3_decode_spec_i_port(cmd, se_tpg, isid_ptr, sa_res_key, all_tg_pt, aptpl); - if (ret != 0) { - rcu_read_unlock(); + if (ret != 0) return ret; - } } - rcu_read_unlock(); return core_scsi3_update_and_write_aptpl(dev, aptpl); } - rcu_read_unlock(); /* ok, existing registration */ @@ -3440,10 +3442,13 @@ after_iport_check: dest_pr_reg = __core_scsi3_locate_pr_reg(dev, dest_node_acl, iport_ptr); if (!dest_pr_reg) { + struct se_lun *dest_lun = rcu_dereference_check(dest_se_deve->se_lun, + atomic_read(&dest_se_deve->pr_kref.refcount) != 0); + spin_unlock(&dev->dev_reservation_lock); - if (core_scsi3_alloc_registration(cmd->se_dev, - dest_node_acl, dest_se_deve, iport_ptr, - sa_res_key, 0, aptpl, 2, 1)) { + if (core_scsi3_alloc_registration(cmd->se_dev, dest_node_acl, + dest_lun, dest_se_deve, dest_se_deve->mapped_lun, + iport_ptr, sa_res_key, 0, aptpl, 2, 1)) { ret = TCM_INVALID_PARAMETER_LIST; goto out; } @@ -4011,10 +4016,10 @@ core_scsi3_pri_read_full_status(struct se_cmd *cmd) * IDENTIFIER field are not defined by this standard. */ if (!pr_reg->pr_reg_all_tg_pt) { - struct se_port *port = pr_reg->pr_reg_tg_pt_lun->lun_sep; + u16 sep_rtpi = pr_reg->tg_pt_sep_rtpi; - buf[off++] = ((port->sep_rtpi >> 8) & 0xff); - buf[off++] = (port->sep_rtpi & 0xff); + buf[off++] = ((sep_rtpi >> 8) & 0xff); + buf[off++] = (sep_rtpi & 0xff); } else off += 2; /* Skip over RELATIVE TARGET PORT IDENTIFIER */ diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 508528a5e927..cf3c6addf05a 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -372,13 +372,14 @@ struct t10_pr_registration { bool isid_present_at_reg; u32 pr_res_mapped_lun; u32 pr_aptpl_target_lun; + u16 tg_pt_sep_rtpi; u32 pr_res_generation; u64 pr_reg_bin_isid; u64 pr_res_key; atomic_t pr_res_holders; struct se_node_acl *pr_reg_nacl; + /* Used by ALL_TG_PT=1 registration with deve->pr_ref taken */ struct se_dev_entry *pr_reg_deve; - struct se_lun *pr_reg_tg_pt_lun; struct list_head pr_reg_list; struct list_head pr_reg_abort_list; struct list_head pr_reg_aptpl_list; @@ -498,7 +499,6 @@ struct se_cmd { struct list_head se_delayed_node; struct list_head se_qf_node; struct se_device *se_dev; - struct se_dev_entry *se_deve; struct se_lun *se_lun; /* Only used for internal passthrough and legacy TCM fabric modules */ struct se_session *se_sess; -- cgit v1.2.3-70-g09d2 From 9fcb57f39c0cde70bcccdc1d998d3060297e911c Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 29 Mar 2015 09:39:03 +0200 Subject: target/pr: cleanup core_scsi3_pr_seq_non_holder Clean up the mess of registered variables, and pass the isid mismatch flag explicitly instead of overloading the registration type. Signed-off-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_pr.c | 44 +++++++++++++++++------------------------ 1 file changed, 18 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 48ed5d2bf5fe..1e89679ad606 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -312,34 +312,31 @@ out: * This function is called by those initiator ports who are *NOT* * the active PR reservation holder when a reservation is present. */ -static int core_scsi3_pr_seq_non_holder( - struct se_cmd *cmd, - u32 pr_reg_type) +static int core_scsi3_pr_seq_non_holder(struct se_cmd *cmd, u32 pr_reg_type, + bool isid_mismatch) { unsigned char *cdb = cmd->t_task_cdb; - struct se_dev_entry *se_deve; struct se_session *se_sess = cmd->se_sess; struct se_node_acl *nacl = se_sess->se_node_acl; - int other_cdb = 0, ignore_reg; + int other_cdb = 0; int registered_nexus = 0, ret = 1; /* Conflict by default */ int all_reg = 0, reg_only = 0; /* ALL_REG, REG_ONLY */ int we = 0; /* Write Exclusive */ int legacy = 0; /* Act like a legacy device and return * RESERVATION CONFLICT on some CDBs */ - bool registered = false; - rcu_read_lock(); - se_deve = target_nacl_find_deve(nacl, cmd->orig_fe_lun); - if (se_deve) - registered = test_bit(DEF_PR_REG_ACTIVE, &se_deve->deve_flags); - rcu_read_unlock(); - /* - * Determine if the registration should be ignored due to - * non-matching ISIDs in target_scsi3_pr_reservation_check(). - */ - ignore_reg = (pr_reg_type & 0x80000000); - if (ignore_reg) - pr_reg_type &= ~0x80000000; + if (isid_mismatch) { + registered_nexus = 0; + } else { + struct se_dev_entry *se_deve; + + rcu_read_lock(); + se_deve = target_nacl_find_deve(nacl, cmd->orig_fe_lun); + if (se_deve) + registered_nexus = test_bit(DEF_PR_REG_ACTIVE, + &se_deve->deve_flags); + rcu_read_unlock(); + } switch (pr_reg_type) { case PR_TYPE_WRITE_EXCLUSIVE: @@ -349,8 +346,6 @@ static int core_scsi3_pr_seq_non_holder( * Some commands are only allowed for the persistent reservation * holder. */ - if ((registered) && !(ignore_reg)) - registered_nexus = 1; break; case PR_TYPE_WRITE_EXCLUSIVE_REGONLY: we = 1; @@ -359,8 +354,6 @@ static int core_scsi3_pr_seq_non_holder( * Some commands are only allowed for registered I_T Nexuses. */ reg_only = 1; - if ((registered) && !(ignore_reg)) - registered_nexus = 1; break; case PR_TYPE_WRITE_EXCLUSIVE_ALLREG: we = 1; @@ -369,8 +362,6 @@ static int core_scsi3_pr_seq_non_holder( * Each registered I_T Nexus is a reservation holder. */ all_reg = 1; - if ((registered) && !(ignore_reg)) - registered_nexus = 1; break; default: return -EINVAL; @@ -576,6 +567,7 @@ target_scsi3_pr_reservation_check(struct se_cmd *cmd) struct se_device *dev = cmd->se_dev; struct se_session *sess = cmd->se_sess; u32 pr_reg_type; + bool isid_mismatch = false; if (!dev->dev_pr_res_holder) return 0; @@ -588,7 +580,7 @@ target_scsi3_pr_reservation_check(struct se_cmd *cmd) if (dev->dev_pr_res_holder->isid_present_at_reg) { if (dev->dev_pr_res_holder->pr_reg_bin_isid != sess->sess_bin_isid) { - pr_reg_type |= 0x80000000; + isid_mismatch = true; goto check_nonholder; } } @@ -596,7 +588,7 @@ target_scsi3_pr_reservation_check(struct se_cmd *cmd) return 0; check_nonholder: - if (core_scsi3_pr_seq_non_holder(cmd, pr_reg_type)) + if (core_scsi3_pr_seq_non_holder(cmd, pr_reg_type, isid_mismatch)) return TCM_RESERVATION_CONFLICT; return 0; } -- cgit v1.2.3-70-g09d2 From 6bb826121be244a5a3c8bd8b7d45c47df18810b7 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Sun, 10 May 2015 19:31:10 -0700 Subject: target: Convert se_portal_group->tpg_lun_list[] to RCU hlist This patch converts the fixed size se_portal_group->tpg_lun_list[] to use modern RCU with hlist_head in order to support an arbitary number of se_lun ports per target endpoint. It includes dropping core_tpg_alloc_lun() from core_dev_add_lun(), and calling it directly from target_fabric_make_lun() to allocate a new se_lun. And add a new target_fabric_port_release() configfs item callback to invoke kfree_rcu() to release memory during se_lun->lun_group shutdown. Also now that se_node_acl->lun_entry_hlist is using RCU, convert existing tpg_lun_lock to struct mutex so core_tpg_add_node_to_devs() can perform RCU updater logic without releasing ->tpg_lun_mutex. Also, drop core_tpg_clear_object_luns() and it's single consumer in iscsi-target, which is duplicating TPG LUN shutdown logic and is current code results in a NOP. Finally, sbp-target and xen-scsiback fabric driver conversions are included, which are required due to the non-standard way they use ->tpg_lun_hlist. Reviewed-by: Hannes Reinecke Cc: Christoph Hellwig Cc: Sagi Grimberg Cc: Paul E. McKenney Cc: Chris Boot Signed-off-by: Nicholas Bellinger --- drivers/target/iscsi/iscsi_target_tpg.c | 2 - drivers/target/sbp/sbp_target.c | 97 +++++++++----------- drivers/target/sbp/sbp_target.h | 2 +- drivers/target/target_core_device.c | 92 ++----------------- drivers/target/target_core_fabric_configfs.c | 34 ++++--- drivers/target/target_core_internal.h | 6 +- drivers/target/target_core_tpg.c | 132 ++++++--------------------- drivers/xen/xen-scsiback.c | 27 +++--- include/target/target_core_base.h | 6 +- include/target/target_core_fabric.h | 1 - 10 files changed, 122 insertions(+), 277 deletions(-) (limited to 'drivers') diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c index d4ac31fc2acd..de8829102ab4 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.c +++ b/drivers/target/iscsi/iscsi_target_tpg.c @@ -278,8 +278,6 @@ int iscsit_tpg_del_portal_group( return -EPERM; } - core_tpg_clear_object_luns(&tpg->tpg_se_tpg); - if (tpg->param_list) { iscsi_release_param_list(tpg->param_list); tpg->param_list = NULL; diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index 5d7755edc668..47fb12fbaf47 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -108,13 +108,13 @@ static struct sbp_session *sbp_session_find_by_guid( } static struct sbp_login_descriptor *sbp_login_find_by_lun( - struct sbp_session *session, struct se_lun *lun) + struct sbp_session *session, u32 unpacked_lun) { struct sbp_login_descriptor *login, *found = NULL; spin_lock_bh(&session->lock); list_for_each_entry(login, &session->login_list, link) { - if (login->lun == lun) + if (login->login_lun == unpacked_lun) found = login; } spin_unlock_bh(&session->lock); @@ -124,7 +124,7 @@ static struct sbp_login_descriptor *sbp_login_find_by_lun( static int sbp_login_count_all_by_lun( struct sbp_tpg *tpg, - struct se_lun *lun, + u32 unpacked_lun, int exclusive) { struct se_session *se_sess; @@ -138,7 +138,7 @@ static int sbp_login_count_all_by_lun( spin_lock_bh(&sess->lock); list_for_each_entry(login, &sess->login_list, link) { - if (login->lun != lun) + if (login->login_lun != unpacked_lun) continue; if (!exclusive || login->exclusive) @@ -174,23 +174,23 @@ static struct sbp_login_descriptor *sbp_login_find_by_id( return found; } -static struct se_lun *sbp_get_lun_from_tpg(struct sbp_tpg *tpg, int lun) +static u32 sbp_get_lun_from_tpg(struct sbp_tpg *tpg, u32 login_lun, int *err) { struct se_portal_group *se_tpg = &tpg->se_tpg; struct se_lun *se_lun; - if (lun >= TRANSPORT_MAX_LUNS_PER_TPG) - return ERR_PTR(-EINVAL); - - spin_lock(&se_tpg->tpg_lun_lock); - se_lun = se_tpg->tpg_lun_list[lun]; - - if (se_lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE) - se_lun = ERR_PTR(-ENODEV); - - spin_unlock(&se_tpg->tpg_lun_lock); + rcu_read_lock(); + hlist_for_each_entry_rcu(se_lun, &se_tpg->tpg_lun_hlist, link) { + if (se_lun->unpacked_lun == login_lun) { + rcu_read_unlock(); + *err = 0; + return login_lun; + } + } + rcu_read_unlock(); - return se_lun; + *err = -ENODEV; + return login_lun; } static struct sbp_session *sbp_session_create( @@ -294,17 +294,16 @@ static void sbp_management_request_login( { struct sbp_tport *tport = agent->tport; struct sbp_tpg *tpg = tport->tpg; - struct se_lun *se_lun; - int ret; - u64 guid; struct sbp_session *sess; struct sbp_login_descriptor *login; struct sbp_login_response_block *response; - int login_response_len; + u64 guid; + u32 unpacked_lun; + int login_response_len, ret; - se_lun = sbp_get_lun_from_tpg(tpg, - LOGIN_ORB_LUN(be32_to_cpu(req->orb.misc))); - if (IS_ERR(se_lun)) { + unpacked_lun = sbp_get_lun_from_tpg(tpg, + LOGIN_ORB_LUN(be32_to_cpu(req->orb.misc)), &ret); + if (ret) { pr_notice("login to unknown LUN: %d\n", LOGIN_ORB_LUN(be32_to_cpu(req->orb.misc))); @@ -325,11 +324,11 @@ static void sbp_management_request_login( } pr_notice("mgt_agent LOGIN to LUN %d from %016llx\n", - se_lun->unpacked_lun, guid); + unpacked_lun, guid); sess = sbp_session_find_by_guid(tpg, guid); if (sess) { - login = sbp_login_find_by_lun(sess, se_lun); + login = sbp_login_find_by_lun(sess, unpacked_lun); if (login) { pr_notice("initiator already logged-in\n"); @@ -357,7 +356,7 @@ static void sbp_management_request_login( * reject with access_denied if any logins present */ if (LOGIN_ORB_EXCLUSIVE(be32_to_cpu(req->orb.misc)) && - sbp_login_count_all_by_lun(tpg, se_lun, 0)) { + sbp_login_count_all_by_lun(tpg, unpacked_lun, 0)) { pr_warn("refusing exclusive login with other active logins\n"); req->status.status = cpu_to_be32( @@ -370,7 +369,7 @@ static void sbp_management_request_login( * check exclusive bit in any existing login descriptor * reject with access_denied if any exclusive logins present */ - if (sbp_login_count_all_by_lun(tpg, se_lun, 1)) { + if (sbp_login_count_all_by_lun(tpg, unpacked_lun, 1)) { pr_warn("refusing login while another exclusive login present\n"); req->status.status = cpu_to_be32( @@ -383,7 +382,7 @@ static void sbp_management_request_login( * check we haven't exceeded the number of allowed logins * reject with resources_unavailable if we have */ - if (sbp_login_count_all_by_lun(tpg, se_lun, 0) >= + if (sbp_login_count_all_by_lun(tpg, unpacked_lun, 0) >= tport->max_logins_per_lun) { pr_warn("max number of logins reached\n"); @@ -439,7 +438,7 @@ static void sbp_management_request_login( } login->sess = sess; - login->lun = se_lun; + login->login_lun = unpacked_lun; login->status_fifo_addr = sbp2_pointer_to_addr(&req->orb.status_fifo); login->exclusive = LOGIN_ORB_EXCLUSIVE(be32_to_cpu(req->orb.misc)); login->login_id = atomic_inc_return(&login_id); @@ -601,7 +600,7 @@ static void sbp_management_request_logout( } pr_info("mgt_agent LOGOUT from LUN %d session %d\n", - login->lun->unpacked_lun, login->login_id); + login->login_lun, login->login_id); if (req->node_addr != login->sess->node_id) { pr_warn("logout from different node ID\n"); @@ -1227,7 +1226,7 @@ static void sbp_handle_command(struct sbp_target_request *req) goto err; } - unpacked_lun = req->login->lun->unpacked_lun; + unpacked_lun = req->login->login_lun; sbp_calc_data_length_direction(req, &data_length, &data_dir); pr_debug("sbp_handle_command ORB:0x%llx unpacked_lun:%d data_len:%d data_dir:%d\n", @@ -1826,25 +1825,21 @@ static int sbp_check_stop_free(struct se_cmd *se_cmd) static int sbp_count_se_tpg_luns(struct se_portal_group *tpg) { - int i, count = 0; - - spin_lock(&tpg->tpg_lun_lock); - for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { - struct se_lun *se_lun = tpg->tpg_lun_list[i]; - - if (se_lun->lun_status == TRANSPORT_LUN_STATUS_FREE) - continue; + struct se_lun *lun; + int count = 0; + rcu_read_lock(); + hlist_for_each_entry_rcu(lun, &tpg->tpg_lun_hlist, link) count++; - } - spin_unlock(&tpg->tpg_lun_lock); + rcu_read_unlock(); return count; } static int sbp_update_unit_directory(struct sbp_tport *tport) { - int num_luns, num_entries, idx = 0, mgt_agt_addr, ret, i; + struct se_lun *lun; + int num_luns, num_entries, idx = 0, mgt_agt_addr, ret; u32 *data; if (tport->unit_directory.data) { @@ -1906,28 +1901,20 @@ static int sbp_update_unit_directory(struct sbp_tport *tport) /* unit unique ID (leaf is just after LUNs) */ data[idx++] = 0x8d000000 | (num_luns + 1); - spin_lock(&tport->tpg->se_tpg.tpg_lun_lock); - for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { - struct se_lun *se_lun = tport->tpg->se_tpg.tpg_lun_list[i]; + rcu_read_lock(); + hlist_for_each_entry_rcu(lun, &tport->tpg->se_tpg.tpg_lun_hlist, link) { struct se_device *dev; int type; - if (se_lun->lun_status == TRANSPORT_LUN_STATUS_FREE) - continue; - - spin_unlock(&tport->tpg->se_tpg.tpg_lun_lock); - - dev = se_lun->lun_se_dev; + dev = lun->lun_se_dev; type = dev->transport->get_device_type(dev); /* logical_unit_number */ data[idx++] = 0x14000000 | ((type << 16) & 0x1f0000) | - (se_lun->unpacked_lun & 0xffff); - - spin_lock(&tport->tpg->se_tpg.tpg_lun_lock); + (lun->unpacked_lun & 0xffff); } - spin_unlock(&tport->tpg->se_tpg.tpg_lun_lock); + rcu_read_unlock(); /* unit unique ID leaf */ data[idx++] = 2 << 16; diff --git a/drivers/target/sbp/sbp_target.h b/drivers/target/sbp/sbp_target.h index e1b0b84f7379..73bcb1208832 100644 --- a/drivers/target/sbp/sbp_target.h +++ b/drivers/target/sbp/sbp_target.h @@ -125,7 +125,7 @@ struct sbp_login_descriptor { struct sbp_session *sess; struct list_head link; - struct se_lun *lun; + u32 login_lun; u64 status_fifo_addr; int exclusive; diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 97792cc81fe4..431e5fc8daec 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -1172,22 +1172,17 @@ int se_dev_set_block_size(struct se_device *dev, u32 block_size) } EXPORT_SYMBOL(se_dev_set_block_size); -struct se_lun *core_dev_add_lun( +int core_dev_add_lun( struct se_portal_group *tpg, struct se_device *dev, - u32 unpacked_lun) + struct se_lun *lun) { - struct se_lun *lun; int rc; - lun = core_tpg_alloc_lun(tpg, unpacked_lun); - if (IS_ERR(lun)) - return lun; - rc = core_tpg_add_lun(tpg, lun, TRANSPORT_LUNFLAGS_READ_WRITE, dev); if (rc < 0) - return ERR_PTR(rc); + return rc; pr_debug("%s_TPG[%u]_LUN[%u] - Activated %s Logical Unit from" " CORE HBA: %u\n", tpg->se_tpg_tfo->get_fabric_name(), @@ -1212,7 +1207,7 @@ struct se_lun *core_dev_add_lun( spin_unlock_irq(&tpg->acl_node_lock); } - return lun; + return 0; } /* core_dev_del_lun(): @@ -1231,68 +1226,6 @@ void core_dev_del_lun( core_tpg_remove_lun(tpg, lun); } -struct se_lun *core_get_lun_from_tpg(struct se_portal_group *tpg, u32 unpacked_lun) -{ - struct se_lun *lun; - - spin_lock(&tpg->tpg_lun_lock); - if (unpacked_lun > (TRANSPORT_MAX_LUNS_PER_TPG-1)) { - pr_err("%s LUN: %u exceeds TRANSPORT_MAX_LUNS" - "_PER_TPG-1: %u for Target Portal Group: %hu\n", - tpg->se_tpg_tfo->get_fabric_name(), unpacked_lun, - TRANSPORT_MAX_LUNS_PER_TPG-1, - tpg->se_tpg_tfo->tpg_get_tag(tpg)); - spin_unlock(&tpg->tpg_lun_lock); - return NULL; - } - lun = tpg->tpg_lun_list[unpacked_lun]; - - if (lun->lun_status != TRANSPORT_LUN_STATUS_FREE) { - pr_err("%s Logical Unit Number: %u is not free on" - " Target Portal Group: %hu, ignoring request.\n", - tpg->se_tpg_tfo->get_fabric_name(), unpacked_lun, - tpg->se_tpg_tfo->tpg_get_tag(tpg)); - spin_unlock(&tpg->tpg_lun_lock); - return NULL; - } - spin_unlock(&tpg->tpg_lun_lock); - - return lun; -} - -/* core_dev_get_lun(): - * - * - */ -static struct se_lun *core_dev_get_lun(struct se_portal_group *tpg, u32 unpacked_lun) -{ - struct se_lun *lun; - - spin_lock(&tpg->tpg_lun_lock); - if (unpacked_lun > (TRANSPORT_MAX_LUNS_PER_TPG-1)) { - pr_err("%s LUN: %u exceeds TRANSPORT_MAX_LUNS_PER" - "_TPG-1: %u for Target Portal Group: %hu\n", - tpg->se_tpg_tfo->get_fabric_name(), unpacked_lun, - TRANSPORT_MAX_LUNS_PER_TPG-1, - tpg->se_tpg_tfo->tpg_get_tag(tpg)); - spin_unlock(&tpg->tpg_lun_lock); - return NULL; - } - lun = tpg->tpg_lun_list[unpacked_lun]; - - if (lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE) { - pr_err("%s Logical Unit Number: %u is not active on" - " Target Portal Group: %hu, ignoring request.\n", - tpg->se_tpg_tfo->get_fabric_name(), unpacked_lun, - tpg->se_tpg_tfo->tpg_get_tag(tpg)); - spin_unlock(&tpg->tpg_lun_lock); - return NULL; - } - spin_unlock(&tpg->tpg_lun_lock); - - return lun; -} - struct se_lun_acl *core_dev_init_initiator_node_lun_acl( struct se_portal_group *tpg, struct se_node_acl *nacl, @@ -1326,22 +1259,11 @@ struct se_lun_acl *core_dev_init_initiator_node_lun_acl( int core_dev_add_initiator_node_lun_acl( struct se_portal_group *tpg, struct se_lun_acl *lacl, - u32 unpacked_lun, + struct se_lun *lun, u32 lun_access) { - struct se_lun *lun; - struct se_node_acl *nacl; + struct se_node_acl *nacl = lacl->se_lun_nacl; - lun = core_dev_get_lun(tpg, unpacked_lun); - if (!lun) { - pr_err("%s Logical Unit Number: %u is not active on" - " Target Portal Group: %hu, ignoring request.\n", - tpg->se_tpg_tfo->get_fabric_name(), unpacked_lun, - tpg->se_tpg_tfo->tpg_get_tag(tpg)); - return -EINVAL; - } - - nacl = lacl->se_lun_nacl; if (!nacl) return -EINVAL; @@ -1362,7 +1284,7 @@ int core_dev_add_initiator_node_lun_acl( pr_debug("%s_TPG[%hu]_LUN[%u->%u] - Added %s ACL for " " InitiatorNode: %s\n", tpg->se_tpg_tfo->get_fabric_name(), - tpg->se_tpg_tfo->tpg_get_tag(tpg), unpacked_lun, lacl->mapped_lun, + tpg->se_tpg_tfo->tpg_get_tag(tpg), lun->unpacked_lun, lacl->mapped_lun, (lun_access & TRANSPORT_LUNFLAGS_READ_WRITE) ? "RW" : "RO", lacl->initiatorname); /* diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index 0939a5492c16..9be8030e016f 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -81,7 +81,7 @@ static int target_fabric_mappedlun_link( struct se_lun_acl, se_lun_group); struct se_portal_group *se_tpg; struct config_item *nacl_ci, *tpg_ci, *tpg_ci_s, *wwn_ci, *wwn_ci_s; - int ret = 0, lun_access; + int lun_access; if (lun->lun_link_magic != SE_LUN_LINK_MAGIC) { pr_err("Bad lun->lun_link_magic, not a valid lun_ci pointer:" @@ -137,12 +137,9 @@ static int target_fabric_mappedlun_link( * Determine the actual mapped LUN value user wants.. * * This value is what the SCSI Initiator actually sees the - * iscsi/$IQN/$TPGT/lun/lun_* as on their SCSI Initiator Ports. + * $FABRIC/$WWPN/$TPGT/lun/lun_* as on their SCSI Initiator Ports. */ - ret = core_dev_add_initiator_node_lun_acl(se_tpg, lacl, - lun->unpacked_lun, lun_access); - - return (ret < 0) ? -EINVAL : 0; + return core_dev_add_initiator_node_lun_acl(se_tpg, lacl, lun, lun_access); } static int target_fabric_mappedlun_unlink( @@ -761,7 +758,6 @@ static int target_fabric_port_link( struct config_item *tpg_ci; struct se_lun *lun = container_of(to_config_group(lun_ci), struct se_lun, lun_group); - struct se_lun *lun_p; struct se_portal_group *se_tpg; struct se_device *dev = container_of(to_config_group(se_dev_ci), struct se_device, dev_group); @@ -789,10 +785,9 @@ static int target_fabric_port_link( return -EEXIST; } - lun_p = core_dev_add_lun(se_tpg, dev, lun->unpacked_lun); - if (IS_ERR(lun_p)) { - pr_err("core_dev_add_lun() failed\n"); - ret = PTR_ERR(lun_p); + ret = core_dev_add_lun(se_tpg, dev, lun); + if (ret) { + pr_err("core_dev_add_lun() failed: %d\n", ret); goto out; } @@ -832,9 +827,18 @@ static int target_fabric_port_unlink( return 0; } +static void target_fabric_port_release(struct config_item *item) +{ + struct se_lun *lun = container_of(to_config_group(item), + struct se_lun, lun_group); + + kfree_rcu(lun, rcu_head); +} + static struct configfs_item_operations target_fabric_port_item_ops = { .show_attribute = target_fabric_port_attr_show, .store_attribute = target_fabric_port_attr_store, + .release = target_fabric_port_release, .allow_link = target_fabric_port_link, .drop_link = target_fabric_port_unlink, }; @@ -893,15 +897,16 @@ static struct config_group *target_fabric_make_lun( if (unpacked_lun > UINT_MAX) return ERR_PTR(-EINVAL); - lun = core_get_lun_from_tpg(se_tpg, unpacked_lun); - if (!lun) - return ERR_PTR(-EINVAL); + lun = core_tpg_alloc_lun(se_tpg, unpacked_lun); + if (IS_ERR(lun)) + return ERR_CAST(lun); lun_cg = &lun->lun_group; lun_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2, GFP_KERNEL); if (!lun_cg->default_groups) { pr_err("Unable to allocate lun_cg->default_groups\n"); + kfree(lun); return ERR_PTR(-ENOMEM); } @@ -918,6 +923,7 @@ static struct config_group *target_fabric_make_lun( if (!port_stat_grp->default_groups) { pr_err("Unable to allocate port_stat_grp->default_groups\n"); kfree(lun_cg->default_groups); + kfree(lun); return ERR_PTR(-ENOMEM); } target_stat_setup_port_default_groups(lun); diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index a04a6e396ae3..2c160ceaf03f 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -23,13 +23,13 @@ int core_dev_export(struct se_device *, struct se_portal_group *, struct se_lun *); void core_dev_unexport(struct se_device *, struct se_portal_group *, struct se_lun *); -struct se_lun *core_dev_add_lun(struct se_portal_group *, struct se_device *, u32); +int core_dev_add_lun(struct se_portal_group *, struct se_device *, + struct se_lun *lun); void core_dev_del_lun(struct se_portal_group *, struct se_lun *); -struct se_lun *core_get_lun_from_tpg(struct se_portal_group *, u32); struct se_lun_acl *core_dev_init_initiator_node_lun_acl(struct se_portal_group *, struct se_node_acl *, u32, int *); int core_dev_add_initiator_node_lun_acl(struct se_portal_group *, - struct se_lun_acl *, u32, u32); + struct se_lun_acl *, struct se_lun *lun, u32); int core_dev_del_initiator_node_lun_acl(struct se_portal_group *, struct se_lun *, struct se_lun_acl *); void core_dev_free_initiator_node_lun_acl(struct se_portal_group *, diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index 0519923ef930..13d34e22a3c4 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -91,19 +91,15 @@ void core_tpg_add_node_to_devs( struct se_node_acl *acl, struct se_portal_group *tpg) { - int i = 0; u32 lun_access = 0; struct se_lun *lun; struct se_device *dev; - spin_lock(&tpg->tpg_lun_lock); - for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { - lun = tpg->tpg_lun_list[i]; + mutex_lock(&tpg->tpg_lun_mutex); + hlist_for_each_entry_rcu(lun, &tpg->tpg_lun_hlist, link) { if (lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE) continue; - spin_unlock(&tpg->tpg_lun_lock); - dev = lun->lun_se_dev; /* * By default in LIO-Target $FABRIC_MOD, @@ -130,7 +126,7 @@ void core_tpg_add_node_to_devs( "READ-WRITE" : "READ-ONLY"); core_enable_device_list_for_node(lun, NULL, lun->unpacked_lun, - lun_access, acl, tpg); + lun_access, acl, tpg); /* * Check to see if there are any existing persistent reservation * APTPL pre-registrations that need to be enabled for this dynamic @@ -138,9 +134,8 @@ void core_tpg_add_node_to_devs( */ core_scsi3_check_aptpl_registration(dev, tpg, lun, acl, lun->unpacked_lun); - spin_lock(&tpg->tpg_lun_lock); } - spin_unlock(&tpg->tpg_lun_lock); + mutex_unlock(&tpg->tpg_lun_mutex); } /* core_set_queue_depth_for_node(): @@ -161,34 +156,6 @@ static int core_set_queue_depth_for_node( return 0; } -void array_free(void *array, int n) -{ - void **a = array; - int i; - - for (i = 0; i < n; i++) - kfree(a[i]); - kfree(a); -} - -static void *array_zalloc(int n, size_t size, gfp_t flags) -{ - void **a; - int i; - - a = kzalloc(n * sizeof(void*), flags); - if (!a) - return NULL; - for (i = 0; i < n; i++) { - a[i] = kzalloc(size, flags); - if (!a[i]) { - array_free(a, n); - return NULL; - } - } - return a; -} - static struct se_node_acl *target_alloc_node_acl(struct se_portal_group *tpg, const unsigned char *initiatorname) { @@ -284,27 +251,6 @@ void core_tpg_wait_for_nacl_pr_ref(struct se_node_acl *nacl) cpu_relax(); } -void core_tpg_clear_object_luns(struct se_portal_group *tpg) -{ - int i; - struct se_lun *lun; - - spin_lock(&tpg->tpg_lun_lock); - for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { - lun = tpg->tpg_lun_list[i]; - - if ((lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE) || - (lun->lun_se_dev == NULL)) - continue; - - spin_unlock(&tpg->tpg_lun_lock); - core_dev_del_lun(tpg, lun); - spin_lock(&tpg->tpg_lun_lock); - } - spin_unlock(&tpg->tpg_lun_lock); -} -EXPORT_SYMBOL(core_tpg_clear_object_luns); - struct se_node_acl *core_tpg_add_initiator_node_acl( struct se_portal_group *tpg, const char *initiatorname) @@ -567,30 +513,7 @@ int core_tpg_register( struct se_portal_group *se_tpg, int proto_id) { - struct se_lun *lun; - u32 i; - - se_tpg->tpg_lun_list = array_zalloc(TRANSPORT_MAX_LUNS_PER_TPG, - sizeof(struct se_lun), GFP_KERNEL); - if (!se_tpg->tpg_lun_list) { - pr_err("Unable to allocate struct se_portal_group->" - "tpg_lun_list\n"); - return -ENOMEM; - } - - for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { - lun = se_tpg->tpg_lun_list[i]; - lun->unpacked_lun = i; - lun->lun_link_magic = SE_LUN_LINK_MAGIC; - lun->lun_status = TRANSPORT_LUN_STATUS_FREE; - atomic_set(&lun->lun_acl_count, 0); - init_completion(&lun->lun_shutdown_comp); - INIT_LIST_HEAD(&lun->lun_acl_list); - spin_lock_init(&lun->lun_acl_lock); - spin_lock_init(&lun->lun_sep_lock); - init_completion(&lun->lun_ref_comp); - } - + INIT_HLIST_HEAD(&se_tpg->tpg_lun_hlist); se_tpg->proto_id = proto_id; se_tpg->se_tpg_tfo = tfo; se_tpg->se_tpg_wwn = se_wwn; @@ -600,14 +523,11 @@ int core_tpg_register( INIT_LIST_HEAD(&se_tpg->tpg_sess_list); spin_lock_init(&se_tpg->acl_node_lock); spin_lock_init(&se_tpg->session_lock); - spin_lock_init(&se_tpg->tpg_lun_lock); + mutex_init(&se_tpg->tpg_lun_mutex); if (se_tpg->proto_id >= 0) { - if (core_tpg_setup_virtual_lun0(se_tpg) < 0) { - array_free(se_tpg->tpg_lun_list, - TRANSPORT_MAX_LUNS_PER_TPG); + if (core_tpg_setup_virtual_lun0(se_tpg) < 0) return -ENOMEM; - } } spin_lock_bh(&tpg_lock); @@ -662,7 +582,6 @@ int core_tpg_deregister(struct se_portal_group *se_tpg) if (se_tpg->proto_id >= 0) core_tpg_remove_lun(se_tpg, &se_tpg->tpg_virt_lun0); - array_free(se_tpg->tpg_lun_list, TRANSPORT_MAX_LUNS_PER_TPG); return 0; } EXPORT_SYMBOL(core_tpg_deregister); @@ -682,17 +601,20 @@ struct se_lun *core_tpg_alloc_lun( return ERR_PTR(-EOVERFLOW); } - spin_lock(&tpg->tpg_lun_lock); - lun = tpg->tpg_lun_list[unpacked_lun]; - if (lun->lun_status == TRANSPORT_LUN_STATUS_ACTIVE) { - pr_err("TPG Logical Unit Number: %u is already active" - " on %s Target Portal Group: %u, ignoring request.\n", - unpacked_lun, tpg->se_tpg_tfo->get_fabric_name(), - tpg->se_tpg_tfo->tpg_get_tag(tpg)); - spin_unlock(&tpg->tpg_lun_lock); - return ERR_PTR(-EINVAL); + lun = kzalloc(sizeof(*lun), GFP_KERNEL); + if (!lun) { + pr_err("Unable to allocate se_lun memory\n"); + return ERR_PTR(-ENOMEM); } - spin_unlock(&tpg->tpg_lun_lock); + lun->unpacked_lun = unpacked_lun; + lun->lun_link_magic = SE_LUN_LINK_MAGIC; + lun->lun_status = TRANSPORT_LUN_STATUS_FREE; + atomic_set(&lun->lun_acl_count, 0); + init_completion(&lun->lun_shutdown_comp); + INIT_LIST_HEAD(&lun->lun_acl_list); + spin_lock_init(&lun->lun_acl_lock); + spin_lock_init(&lun->lun_sep_lock); + init_completion(&lun->lun_ref_comp); return lun; } @@ -716,10 +638,12 @@ int core_tpg_add_lun( return ret; } - spin_lock(&tpg->tpg_lun_lock); + mutex_lock(&tpg->tpg_lun_mutex); lun->lun_access = lun_access; lun->lun_status = TRANSPORT_LUN_STATUS_ACTIVE; - spin_unlock(&tpg->tpg_lun_lock); + if (!(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) + hlist_add_head_rcu(&lun->link, &tpg->tpg_lun_hlist); + mutex_unlock(&tpg->tpg_lun_mutex); return 0; } @@ -728,14 +652,18 @@ void core_tpg_remove_lun( struct se_portal_group *tpg, struct se_lun *lun) { + struct se_device *dev = lun->lun_se_dev; + core_clear_lun_from_tpg(lun, tpg); transport_clear_lun_ref(lun); core_dev_unexport(lun->lun_se_dev, tpg, lun); - spin_lock(&tpg->tpg_lun_lock); + mutex_lock(&tpg->tpg_lun_mutex); lun->lun_status = TRANSPORT_LUN_STATUS_FREE; - spin_unlock(&tpg->tpg_lun_lock); + if (!(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) + hlist_del_rcu(&lun->link); + mutex_unlock(&tpg->tpg_lun_mutex); percpu_ref_exit(&lun->lun_ref); } diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index 8b7dd47abd8d..555033bd9239 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -866,7 +866,8 @@ static int scsiback_add_translation_entry(struct vscsibk_info *info, struct list_head *head = &(info->v2p_entry_lists); unsigned long flags; char *lunp; - unsigned int lun; + unsigned int unpacked_lun; + struct se_lun *se_lun; struct scsiback_tpg *tpg_entry, *tpg = NULL; char *error = "doesn't exist"; @@ -877,7 +878,7 @@ static int scsiback_add_translation_entry(struct vscsibk_info *info, } *lunp = 0; lunp++; - if (kstrtouint(lunp, 10, &lun) || lun >= TRANSPORT_MAX_LUNS_PER_TPG) { + if (kstrtouint(lunp, 10, &unpacked_lun) || unpacked_lun >= TRANSPORT_MAX_LUNS_PER_TPG) { pr_err("lun number not valid: %s\n", lunp); return -EINVAL; } @@ -886,15 +887,17 @@ static int scsiback_add_translation_entry(struct vscsibk_info *info, list_for_each_entry(tpg_entry, &scsiback_list, tv_tpg_list) { if (!strcmp(phy, tpg_entry->tport->tport_name) || !strcmp(phy, tpg_entry->param_alias)) { - spin_lock(&tpg_entry->se_tpg.tpg_lun_lock); - if (tpg_entry->se_tpg.tpg_lun_list[lun]->lun_status == - TRANSPORT_LUN_STATUS_ACTIVE) { - if (!tpg_entry->tpg_nexus) - error = "nexus undefined"; - else - tpg = tpg_entry; + mutex_lock(&tpg_entry->se_tpg.tpg_lun_mutex); + hlist_for_each_entry(se_lun, &tpg_entry->se_tpg.tpg_lun_hlist, link) { + if (se_lun->unpacked_lun == unpacked_lun) { + if (!tpg_entry->tpg_nexus) + error = "nexus undefined"; + else + tpg = tpg_entry; + break; + } } - spin_unlock(&tpg_entry->se_tpg.tpg_lun_lock); + mutex_unlock(&tpg_entry->se_tpg.tpg_lun_mutex); break; } } @@ -906,7 +909,7 @@ static int scsiback_add_translation_entry(struct vscsibk_info *info, mutex_unlock(&scsiback_mutex); if (!tpg) { - pr_err("%s:%d %s\n", phy, lun, error); + pr_err("%s:%d %s\n", phy, unpacked_lun, error); return -ENODEV; } @@ -934,7 +937,7 @@ static int scsiback_add_translation_entry(struct vscsibk_info *info, kref_init(&new->kref); new->v = *v; new->tpg = tpg; - new->lun = lun; + new->lun = unpacked_lun; list_add_tail(&new->l, head); out: diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index cf3c6addf05a..c15fa1a3b945 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -725,6 +725,8 @@ struct se_lun { struct se_port_stat_grps port_stat_grps; struct completion lun_ref_comp; struct percpu_ref lun_ref; + struct hlist_node link; + struct rcu_head rcu_head; }; struct se_dev_stat_grps { @@ -877,11 +879,11 @@ struct se_portal_group { spinlock_t acl_node_lock; /* Spinlock for adding/removing sessions */ spinlock_t session_lock; - spinlock_t tpg_lun_lock; + struct mutex tpg_lun_mutex; struct list_head se_tpg_node; /* linked list for initiator ACL list */ struct list_head acl_node_list; - struct se_lun **tpg_lun_list; + struct hlist_head tpg_lun_hlist; struct se_lun tpg_virt_lun0; /* List of TCM sessions associated wth this TPG */ struct list_head tpg_sess_list; diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index 55654c90350d..b1e00a7d66de 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -157,7 +157,6 @@ struct se_node_acl *core_tpg_get_initiator_node_acl(struct se_portal_group *tpg, unsigned char *); struct se_node_acl *core_tpg_check_initiator_node_acl(struct se_portal_group *, unsigned char *); -void core_tpg_clear_object_luns(struct se_portal_group *); int core_tpg_set_initiator_node_queue_depth(struct se_portal_group *, unsigned char *, u32, int); int core_tpg_set_initiator_node_tag(struct se_portal_group *, -- cgit v1.2.3-70-g09d2 From 403edd78a2851ef95b24c0bf5151a4ab640898d7 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Sun, 8 Mar 2015 22:33:47 +0000 Subject: target: Convert se_tpg->acl_node_lock to ->acl_node_mutex This patch converts se_tpg->acl_node_lock to struct mutex, so that ->acl_node_acl walkers in core_clear_lun_from_tpg() can block when calling core_disable_device_list_for_node(). It also updates core_dev_add_lun() to hold ->acl_node_mutex when calling core_tpg_add_node_to_devs() to build ->lun_entry_hlist for dynamically generated se_node_acl. Reviewed-by: Hannes Reinecke Cc: Christoph Hellwig Cc: Sagi Grimberg Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_device.c | 14 ++++------ drivers/target/target_core_pr.c | 8 +++--- drivers/target/target_core_tpg.c | 51 +++++++++++++++++----------------- drivers/target/target_core_transport.c | 20 ++++++------- drivers/target/tcm_fc/tfc_conf.c | 4 +-- include/target/target_core_base.h | 2 +- 6 files changed, 48 insertions(+), 51 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 431e5fc8daec..1593d4965848 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -440,9 +440,8 @@ void core_clear_lun_from_tpg(struct se_lun *lun, struct se_portal_group *tpg) struct se_node_acl *nacl; struct se_dev_entry *deve; - spin_lock_irq(&tpg->acl_node_lock); + mutex_lock(&tpg->acl_node_mutex); list_for_each_entry(nacl, &tpg->acl_node_list, acl_list) { - spin_unlock_irq(&tpg->acl_node_lock); mutex_lock(&nacl->lun_entry_mutex); hlist_for_each_entry_rcu(deve, &nacl->lun_entry_hlist, link) { @@ -455,10 +454,8 @@ void core_clear_lun_from_tpg(struct se_lun *lun, struct se_portal_group *tpg) core_disable_device_list_for_node(lun, deve, nacl, tpg); } mutex_unlock(&nacl->lun_entry_mutex); - - spin_lock_irq(&tpg->acl_node_lock); } - spin_unlock_irq(&tpg->acl_node_lock); + mutex_unlock(&tpg->acl_node_mutex); } static struct se_port *core_alloc_port(struct se_device *dev) @@ -1194,17 +1191,16 @@ int core_dev_add_lun( */ if (tpg->se_tpg_tfo->tpg_check_demo_mode(tpg)) { struct se_node_acl *acl; - spin_lock_irq(&tpg->acl_node_lock); + + mutex_lock(&tpg->acl_node_mutex); list_for_each_entry(acl, &tpg->acl_node_list, acl_list) { if (acl->dynamic_node_acl && (!tpg->se_tpg_tfo->tpg_check_demo_mode_login_only || !tpg->se_tpg_tfo->tpg_check_demo_mode_login_only(tpg))) { - spin_unlock_irq(&tpg->acl_node_lock); core_tpg_add_node_to_devs(acl, tpg); - spin_lock_irq(&tpg->acl_node_lock); } } - spin_unlock_irq(&tpg->acl_node_lock); + mutex_unlock(&tpg->acl_node_mutex); } return 0; diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 1e89679ad606..b983f8a54766 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -1589,12 +1589,12 @@ core_scsi3_decode_spec_i_port( * from the decoded fabric module specific TransportID * at *i_str. */ - spin_lock_irq(&tmp_tpg->acl_node_lock); + mutex_lock(&tmp_tpg->acl_node_mutex); dest_node_acl = __core_tpg_get_initiator_node_acl( tmp_tpg, i_str); if (dest_node_acl) atomic_inc_mb(&dest_node_acl->acl_pr_ref_count); - spin_unlock_irq(&tmp_tpg->acl_node_lock); + mutex_unlock(&tmp_tpg->acl_node_mutex); if (!dest_node_acl) { core_scsi3_tpg_undepend_item(tmp_tpg); @@ -3308,12 +3308,12 @@ after_iport_check: /* * Locate the destination struct se_node_acl from the received Transport ID */ - spin_lock_irq(&dest_se_tpg->acl_node_lock); + mutex_lock(&dest_se_tpg->acl_node_mutex); dest_node_acl = __core_tpg_get_initiator_node_acl(dest_se_tpg, initiator_str); if (dest_node_acl) atomic_inc_mb(&dest_node_acl->acl_pr_ref_count); - spin_unlock_irq(&dest_se_tpg->acl_node_lock); + mutex_unlock(&dest_se_tpg->acl_node_mutex); if (!dest_node_acl) { pr_err("Unable to locate %s dest_node_acl for" diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index 13d34e22a3c4..229e8278f4fe 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -49,7 +49,7 @@ static LIST_HEAD(tpg_list); /* __core_tpg_get_initiator_node_acl(): * - * spin_lock_bh(&tpg->acl_node_lock); must be held when calling + * mutex_lock(&tpg->acl_node_mutex); must be held when calling */ struct se_node_acl *__core_tpg_get_initiator_node_acl( struct se_portal_group *tpg, @@ -75,9 +75,9 @@ struct se_node_acl *core_tpg_get_initiator_node_acl( { struct se_node_acl *acl; - spin_lock_irq(&tpg->acl_node_lock); + mutex_lock(&tpg->acl_node_mutex); acl = __core_tpg_get_initiator_node_acl(tpg, initiatorname); - spin_unlock_irq(&tpg->acl_node_lock); + mutex_unlock(&tpg->acl_node_mutex); return acl; } @@ -198,10 +198,10 @@ static void target_add_node_acl(struct se_node_acl *acl) { struct se_portal_group *tpg = acl->se_tpg; - spin_lock_irq(&tpg->acl_node_lock); + mutex_lock(&tpg->acl_node_mutex); list_add_tail(&acl->acl_list, &tpg->acl_node_list); tpg->num_node_acls++; - spin_unlock_irq(&tpg->acl_node_lock); + mutex_unlock(&tpg->acl_node_mutex); pr_debug("%s_TPG[%hu] - Added %s ACL with TCQ Depth: %d for %s" " Initiator Node: %s\n", @@ -257,7 +257,7 @@ struct se_node_acl *core_tpg_add_initiator_node_acl( { struct se_node_acl *acl; - spin_lock_irq(&tpg->acl_node_lock); + mutex_lock(&tpg->acl_node_mutex); acl = __core_tpg_get_initiator_node_acl(tpg, initiatorname); if (acl) { if (acl->dynamic_node_acl) { @@ -265,7 +265,7 @@ struct se_node_acl *core_tpg_add_initiator_node_acl( pr_debug("%s_TPG[%u] - Replacing dynamic ACL" " for %s\n", tpg->se_tpg_tfo->get_fabric_name(), tpg->se_tpg_tfo->tpg_get_tag(tpg), initiatorname); - spin_unlock_irq(&tpg->acl_node_lock); + mutex_unlock(&tpg->acl_node_mutex); return acl; } @@ -273,10 +273,10 @@ struct se_node_acl *core_tpg_add_initiator_node_acl( " Node %s already exists for TPG %u, ignoring" " request.\n", tpg->se_tpg_tfo->get_fabric_name(), initiatorname, tpg->se_tpg_tfo->tpg_get_tag(tpg)); - spin_unlock_irq(&tpg->acl_node_lock); + mutex_unlock(&tpg->acl_node_mutex); return ERR_PTR(-EEXIST); } - spin_unlock_irq(&tpg->acl_node_lock); + mutex_unlock(&tpg->acl_node_mutex); acl = target_alloc_node_acl(tpg, initiatorname); if (!acl) @@ -294,13 +294,13 @@ void core_tpg_del_initiator_node_acl(struct se_node_acl *acl) unsigned long flags; int rc; - spin_lock_irq(&tpg->acl_node_lock); + mutex_lock(&tpg->acl_node_mutex); if (acl->dynamic_node_acl) { acl->dynamic_node_acl = 0; } list_del(&acl->acl_list); tpg->num_node_acls--; - spin_unlock_irq(&tpg->acl_node_lock); + mutex_unlock(&tpg->acl_node_mutex); spin_lock_irqsave(&acl->nacl_sess_lock, flags); acl->acl_stop = 1; @@ -357,21 +357,21 @@ int core_tpg_set_initiator_node_queue_depth( unsigned long flags; int dynamic_acl = 0; - spin_lock_irq(&tpg->acl_node_lock); + mutex_lock(&tpg->acl_node_mutex); acl = __core_tpg_get_initiator_node_acl(tpg, initiatorname); if (!acl) { pr_err("Access Control List entry for %s Initiator" " Node %s does not exists for TPG %hu, ignoring" " request.\n", tpg->se_tpg_tfo->get_fabric_name(), initiatorname, tpg->se_tpg_tfo->tpg_get_tag(tpg)); - spin_unlock_irq(&tpg->acl_node_lock); + mutex_unlock(&tpg->acl_node_mutex); return -ENODEV; } if (acl->dynamic_node_acl) { acl->dynamic_node_acl = 0; dynamic_acl = 1; } - spin_unlock_irq(&tpg->acl_node_lock); + mutex_unlock(&tpg->acl_node_mutex); spin_lock_irqsave(&tpg->session_lock, flags); list_for_each_entry(sess, &tpg->tpg_sess_list, sess_list) { @@ -387,10 +387,10 @@ int core_tpg_set_initiator_node_queue_depth( tpg->se_tpg_tfo->get_fabric_name(), initiatorname); spin_unlock_irqrestore(&tpg->session_lock, flags); - spin_lock_irq(&tpg->acl_node_lock); + mutex_lock(&tpg->acl_node_mutex); if (dynamic_acl) acl->dynamic_node_acl = 1; - spin_unlock_irq(&tpg->acl_node_lock); + mutex_unlock(&tpg->acl_node_mutex); return -EEXIST; } /* @@ -425,10 +425,10 @@ int core_tpg_set_initiator_node_queue_depth( if (init_sess) tpg->se_tpg_tfo->close_session(init_sess); - spin_lock_irq(&tpg->acl_node_lock); + mutex_lock(&tpg->acl_node_mutex); if (dynamic_acl) acl->dynamic_node_acl = 1; - spin_unlock_irq(&tpg->acl_node_lock); + mutex_unlock(&tpg->acl_node_mutex); return -EINVAL; } spin_unlock_irqrestore(&tpg->session_lock, flags); @@ -444,10 +444,10 @@ int core_tpg_set_initiator_node_queue_depth( initiatorname, tpg->se_tpg_tfo->get_fabric_name(), tpg->se_tpg_tfo->tpg_get_tag(tpg)); - spin_lock_irq(&tpg->acl_node_lock); + mutex_lock(&tpg->acl_node_mutex); if (dynamic_acl) acl->dynamic_node_acl = 1; - spin_unlock_irq(&tpg->acl_node_lock); + mutex_unlock(&tpg->acl_node_mutex); return 0; } @@ -521,9 +521,9 @@ int core_tpg_register( INIT_LIST_HEAD(&se_tpg->acl_node_list); INIT_LIST_HEAD(&se_tpg->se_tpg_node); INIT_LIST_HEAD(&se_tpg->tpg_sess_list); - spin_lock_init(&se_tpg->acl_node_lock); spin_lock_init(&se_tpg->session_lock); mutex_init(&se_tpg->tpg_lun_mutex); + mutex_init(&se_tpg->acl_node_mutex); if (se_tpg->proto_id >= 0) { if (core_tpg_setup_virtual_lun0(se_tpg) < 0) @@ -559,25 +559,26 @@ int core_tpg_deregister(struct se_portal_group *se_tpg) while (atomic_read(&se_tpg->tpg_pr_ref_count) != 0) cpu_relax(); + /* * Release any remaining demo-mode generated se_node_acl that have * not been released because of TFO->tpg_check_demo_mode_cache() == 1 * in transport_deregister_session(). */ - spin_lock_irq(&se_tpg->acl_node_lock); + mutex_lock(&se_tpg->acl_node_mutex); list_for_each_entry_safe(nacl, nacl_tmp, &se_tpg->acl_node_list, acl_list) { list_del(&nacl->acl_list); se_tpg->num_node_acls--; - spin_unlock_irq(&se_tpg->acl_node_lock); + mutex_unlock(&se_tpg->acl_node_mutex); core_tpg_wait_for_nacl_pr_ref(nacl); core_free_device_list_for_node(nacl, se_tpg); kfree(nacl); - spin_lock_irq(&se_tpg->acl_node_lock); + mutex_lock(&se_tpg->acl_node_mutex); } - spin_unlock_irq(&se_tpg->acl_node_lock); + mutex_unlock(&se_tpg->acl_node_mutex); if (se_tpg->proto_id >= 0) core_tpg_remove_lun(se_tpg, &se_tpg->tpg_virt_lun0); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 3c2809cd8b5b..965a308e10a5 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -498,7 +498,7 @@ void transport_deregister_session(struct se_session *se_sess) const struct target_core_fabric_ops *se_tfo; struct se_node_acl *se_nacl; unsigned long flags; - bool comp_nacl = true; + bool comp_nacl = true, drop_nacl = false; if (!se_tpg) { transport_free_session(se_sess); @@ -518,22 +518,22 @@ void transport_deregister_session(struct se_session *se_sess) */ se_nacl = se_sess->se_node_acl; - spin_lock_irqsave(&se_tpg->acl_node_lock, flags); + mutex_lock(&se_tpg->acl_node_mutex); if (se_nacl && se_nacl->dynamic_node_acl) { if (!se_tfo->tpg_check_demo_mode_cache(se_tpg)) { list_del(&se_nacl->acl_list); se_tpg->num_node_acls--; - spin_unlock_irqrestore(&se_tpg->acl_node_lock, flags); - core_tpg_wait_for_nacl_pr_ref(se_nacl); - core_free_device_list_for_node(se_nacl, se_tpg); - kfree(se_nacl); - - comp_nacl = false; - spin_lock_irqsave(&se_tpg->acl_node_lock, flags); + drop_nacl = true; } } - spin_unlock_irqrestore(&se_tpg->acl_node_lock, flags); + mutex_unlock(&se_tpg->acl_node_mutex); + if (drop_nacl) { + core_tpg_wait_for_nacl_pr_ref(se_nacl); + core_free_device_list_for_node(se_nacl, se_tpg); + kfree(se_nacl); + comp_nacl = false; + } pr_debug("TARGET_CORE[%s]: Deregistered fabric_sess\n", se_tpg->se_tpg_tfo->get_fabric_name()); /* diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c index ee5653139417..8e1a54f2642c 100644 --- a/drivers/target/tcm_fc/tfc_conf.c +++ b/drivers/target/tcm_fc/tfc_conf.c @@ -217,7 +217,7 @@ struct ft_node_acl *ft_acl_get(struct ft_tpg *tpg, struct fc_rport_priv *rdata) struct se_portal_group *se_tpg = &tpg->se_tpg; struct se_node_acl *se_acl; - spin_lock_irq(&se_tpg->acl_node_lock); + mutex_lock(&se_tpg->acl_node_mutex); list_for_each_entry(se_acl, &se_tpg->acl_node_list, acl_list) { acl = container_of(se_acl, struct ft_node_acl, se_node_acl); pr_debug("acl %p port_name %llx\n", @@ -231,7 +231,7 @@ struct ft_node_acl *ft_acl_get(struct ft_tpg *tpg, struct fc_rport_priv *rdata) break; } } - spin_unlock_irq(&se_tpg->acl_node_lock); + mutex_unlock(&se_tpg->acl_node_mutex); return found; } diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index c15fa1a3b945..2b6adace28b4 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -876,7 +876,7 @@ struct se_portal_group { /* Used for PR SPEC_I_PT=1 and REGISTER_AND_MOVE */ atomic_t tpg_pr_ref_count; /* Spinlock for adding/removing ACLed Nodes */ - spinlock_t acl_node_lock; + struct mutex acl_node_mutex; /* Spinlock for adding/removing sessions */ spinlock_t session_lock; struct mutex tpg_lun_mutex; -- cgit v1.2.3-70-g09d2 From 22793de590ca23a1e49b0ce5353911121fcc32be Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Fri, 6 Mar 2015 10:23:25 +0000 Subject: target: Convert core_tpg_deregister to use list splice This patch converts core_tpg_deregister() to perform a list splice for any remaining dynamically generated se_node_acls attached to se_tpg, before calling kfree(nacl) to free memory. Reviewed-by: Hannes Reinecke Cc: Christoph Hellwig Cc: Sagi Grimberg Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_tpg.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index 229e8278f4fe..e7745d21075b 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -547,6 +547,7 @@ int core_tpg_deregister(struct se_portal_group *se_tpg) { const struct target_core_fabric_ops *tfo = se_tpg->se_tpg_tfo; struct se_node_acl *nacl, *nacl_tmp; + LIST_HEAD(node_list); pr_debug("TARGET_CORE[%s]: Deallocating portal_group for endpoint: %s, " "Proto: %d, Portal Tag: %u\n", tfo->get_fabric_name(), @@ -560,25 +561,22 @@ int core_tpg_deregister(struct se_portal_group *se_tpg) while (atomic_read(&se_tpg->tpg_pr_ref_count) != 0) cpu_relax(); + mutex_lock(&se_tpg->acl_node_mutex); + list_splice_init(&se_tpg->acl_node_list, &node_list); + mutex_unlock(&se_tpg->acl_node_mutex); /* * Release any remaining demo-mode generated se_node_acl that have * not been released because of TFO->tpg_check_demo_mode_cache() == 1 * in transport_deregister_session(). */ - mutex_lock(&se_tpg->acl_node_mutex); - list_for_each_entry_safe(nacl, nacl_tmp, &se_tpg->acl_node_list, - acl_list) { + list_for_each_entry_safe(nacl, nacl_tmp, &node_list, acl_list) { list_del(&nacl->acl_list); se_tpg->num_node_acls--; - mutex_unlock(&se_tpg->acl_node_mutex); core_tpg_wait_for_nacl_pr_ref(nacl); core_free_device_list_for_node(nacl, se_tpg); kfree(nacl); - - mutex_lock(&se_tpg->acl_node_mutex); } - mutex_unlock(&se_tpg->acl_node_mutex); if (se_tpg->proto_id >= 0) core_tpg_remove_lun(se_tpg, &se_tpg->tpg_virt_lun0); -- cgit v1.2.3-70-g09d2 From 84786546b6ff8d50c3e4c1ea877a872cf55d485a Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Sun, 8 Mar 2015 08:04:44 +0000 Subject: target: Drop unused se_lun->lun_acl_list Reviewed-by: Hannes Reinecke Cc: Christoph Hellwig Cc: Sagi Grimberg Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_device.c | 15 --------------- drivers/target/target_core_tpg.c | 4 ---- include/target/target_core_base.h | 3 --- 3 files changed, 22 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 1593d4965848..ba8c65a670d8 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -1243,7 +1243,6 @@ struct se_lun_acl *core_dev_init_initiator_node_lun_acl( return NULL; } - INIT_LIST_HEAD(&lacl->lacl_list); lacl->mapped_lun = mapped_lun; lacl->se_lun_nacl = nacl; snprintf(lacl->initiatorname, TRANSPORT_IQN_LEN, "%s", @@ -1273,11 +1272,6 @@ int core_dev_add_initiator_node_lun_acl( lun_access, nacl, tpg) < 0) return -EINVAL; - spin_lock(&lun->lun_acl_lock); - list_add_tail(&lacl->lacl_list, &lun->lun_acl_list); - atomic_inc_mb(&lun->lun_acl_count); - spin_unlock(&lun->lun_acl_lock); - pr_debug("%s_TPG[%hu]_LUN[%u->%u] - Added %s ACL for " " InitiatorNode: %s\n", tpg->se_tpg_tfo->get_fabric_name(), tpg->se_tpg_tfo->tpg_get_tag(tpg), lun->unpacked_lun, lacl->mapped_lun, @@ -1304,19 +1298,12 @@ int core_dev_del_initiator_node_lun_acl( if (!nacl) return -EINVAL; - spin_lock(&lun->lun_acl_lock); - list_del(&lacl->lacl_list); - atomic_dec_mb(&lun->lun_acl_count); - spin_unlock(&lun->lun_acl_lock); - mutex_lock(&nacl->lun_entry_mutex); deve = target_nacl_find_deve(nacl, lacl->mapped_lun); if (deve) core_disable_device_list_for_node(lun, deve, nacl, tpg); mutex_unlock(&nacl->lun_entry_mutex); - lacl->se_lun = NULL; - pr_debug("%s_TPG[%hu]_LUN[%u] - Removed ACL for" " InitiatorNode: %s Mapped LUN: %u\n", tpg->se_tpg_tfo->get_fabric_name(), @@ -1446,8 +1433,6 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name) xcopy_lun = &dev->xcopy_lun; xcopy_lun->lun_se_dev = dev; init_completion(&xcopy_lun->lun_shutdown_comp); - INIT_LIST_HEAD(&xcopy_lun->lun_acl_list); - spin_lock_init(&xcopy_lun->lun_acl_lock); spin_lock_init(&xcopy_lun->lun_sep_lock); init_completion(&xcopy_lun->lun_ref_comp); diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index e7745d21075b..73c25bda5a25 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -495,8 +495,6 @@ static int core_tpg_setup_virtual_lun0(struct se_portal_group *se_tpg) lun->lun_status = TRANSPORT_LUN_STATUS_FREE; atomic_set(&lun->lun_acl_count, 0); init_completion(&lun->lun_shutdown_comp); - INIT_LIST_HEAD(&lun->lun_acl_list); - spin_lock_init(&lun->lun_acl_lock); spin_lock_init(&lun->lun_sep_lock); init_completion(&lun->lun_ref_comp); @@ -610,8 +608,6 @@ struct se_lun *core_tpg_alloc_lun( lun->lun_status = TRANSPORT_LUN_STATUS_FREE; atomic_set(&lun->lun_acl_count, 0); init_completion(&lun->lun_shutdown_comp); - INIT_LIST_HEAD(&lun->lun_acl_list); - spin_lock_init(&lun->lun_acl_lock); spin_lock_init(&lun->lun_sep_lock); init_completion(&lun->lun_ref_comp); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 2b6adace28b4..7908d6d04f91 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -632,7 +632,6 @@ struct se_lun_acl { u32 mapped_lun; struct se_node_acl *se_lun_nacl; struct se_lun *se_lun; - struct list_head lacl_list; struct config_group se_lun_group; struct se_ml_stat_grps ml_stat_grps; }; @@ -715,10 +714,8 @@ struct se_lun { u32 unpacked_lun; u32 lun_index; atomic_t lun_acl_count; - spinlock_t lun_acl_lock; spinlock_t lun_sep_lock; struct completion lun_shutdown_comp; - struct list_head lun_acl_list; struct se_device *lun_se_dev; struct se_port *lun_sep; struct config_group lun_group; -- cgit v1.2.3-70-g09d2 From df9766ca9da5d9c1f2bb4eea9c9f16a2e7e8e1a5 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Fri, 22 May 2015 02:05:19 +0000 Subject: target: Only reset specific dynamic entries during lun_group creation This patch changes core_tpg_add_node_to_devs() to avoid unnecessarly resetting every se_dev_entry in se_node_acl->tpg_lun_hlist when the operation is driven by an explicit configfs se_lun->lun_group creation via core_dev_add_lun() to only update a single se_lun. Otherwise for the second core_tpg_check_initiator_node_acl() case, go ahead and continue to scan the full set of currently active se_lun in se_portal_group->tpg_lun_hlist. Reviewed-by: Hannes Reinecke Cc: Christoph Hellwig Cc: Sagi Grimberg Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_device.c | 2 +- drivers/target/target_core_internal.h | 3 ++- drivers/target/target_core_tpg.c | 7 +++++-- 3 files changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index ba8c65a670d8..47a73609e277 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -1197,7 +1197,7 @@ int core_dev_add_lun( if (acl->dynamic_node_acl && (!tpg->se_tpg_tfo->tpg_check_demo_mode_login_only || !tpg->se_tpg_tfo->tpg_check_demo_mode_login_only(tpg))) { - core_tpg_add_node_to_devs(acl, tpg); + core_tpg_add_node_to_devs(acl, tpg, lun); } } mutex_unlock(&tpg->acl_node_mutex); diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index 2c160ceaf03f..ce80ca76f68b 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -64,7 +64,8 @@ extern struct se_device *g_lun0_dev; struct se_node_acl *__core_tpg_get_initiator_node_acl(struct se_portal_group *tpg, const char *); -void core_tpg_add_node_to_devs(struct se_node_acl *, struct se_portal_group *); +void core_tpg_add_node_to_devs(struct se_node_acl *, struct se_portal_group *, + struct se_lun *); void core_tpg_wait_for_nacl_pr_ref(struct se_node_acl *); struct se_lun *core_tpg_alloc_lun(struct se_portal_group *, u32); int core_tpg_add_lun(struct se_portal_group *, struct se_lun *, diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index 73c25bda5a25..f66c208386f8 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -89,7 +89,8 @@ EXPORT_SYMBOL(core_tpg_get_initiator_node_acl); */ void core_tpg_add_node_to_devs( struct se_node_acl *acl, - struct se_portal_group *tpg) + struct se_portal_group *tpg, + struct se_lun *lun_orig) { u32 lun_access = 0; struct se_lun *lun; @@ -99,6 +100,8 @@ void core_tpg_add_node_to_devs( hlist_for_each_entry_rcu(lun, &tpg->tpg_lun_hlist, link) { if (lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE) continue; + if (lun_orig && lun != lun_orig) + continue; dev = lun->lun_se_dev; /* @@ -238,7 +241,7 @@ struct se_node_acl *core_tpg_check_initiator_node_acl( */ if ((tpg->se_tpg_tfo->tpg_check_demo_mode_login_only == NULL) || (tpg->se_tpg_tfo->tpg_check_demo_mode_login_only(tpg) != 1)) - core_tpg_add_node_to_devs(acl, tpg); + core_tpg_add_node_to_devs(acl, tpg, NULL); target_add_node_acl(acl); return acl; -- cgit v1.2.3-70-g09d2 From 4624773765699ac3f4e0b918306b638cba385713 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Sun, 24 May 2015 00:48:54 -0700 Subject: target: Drop left-over se_lun->lun_status Now that se_portal_group->tpg_lun_hlist is a RCU protected hlist, go ahead and drop the left-over lun->lun_status usage. Reported-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_tpg.c | 6 ------ include/target/target_core_base.h | 8 -------- 2 files changed, 14 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index f66c208386f8..91f8ddb6d783 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -98,8 +98,6 @@ void core_tpg_add_node_to_devs( mutex_lock(&tpg->tpg_lun_mutex); hlist_for_each_entry_rcu(lun, &tpg->tpg_lun_hlist, link) { - if (lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE) - continue; if (lun_orig && lun != lun_orig) continue; @@ -495,7 +493,6 @@ static int core_tpg_setup_virtual_lun0(struct se_portal_group *se_tpg) int ret; lun->unpacked_lun = 0; - lun->lun_status = TRANSPORT_LUN_STATUS_FREE; atomic_set(&lun->lun_acl_count, 0); init_completion(&lun->lun_shutdown_comp); spin_lock_init(&lun->lun_sep_lock); @@ -608,7 +605,6 @@ struct se_lun *core_tpg_alloc_lun( } lun->unpacked_lun = unpacked_lun; lun->lun_link_magic = SE_LUN_LINK_MAGIC; - lun->lun_status = TRANSPORT_LUN_STATUS_FREE; atomic_set(&lun->lun_acl_count, 0); init_completion(&lun->lun_shutdown_comp); spin_lock_init(&lun->lun_sep_lock); @@ -638,7 +634,6 @@ int core_tpg_add_lun( mutex_lock(&tpg->tpg_lun_mutex); lun->lun_access = lun_access; - lun->lun_status = TRANSPORT_LUN_STATUS_ACTIVE; if (!(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) hlist_add_head_rcu(&lun->link, &tpg->tpg_lun_hlist); mutex_unlock(&tpg->tpg_lun_mutex); @@ -658,7 +653,6 @@ void core_tpg_remove_lun( core_dev_unexport(lun->lun_se_dev, tpg, lun); mutex_lock(&tpg->tpg_lun_mutex); - lun->lun_status = TRANSPORT_LUN_STATUS_FREE; if (!(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) hlist_del_rcu(&lun->link); mutex_unlock(&tpg->tpg_lun_mutex); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 7908d6d04f91..78ed2a83838c 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -119,12 +119,6 @@ enum hba_flags_table { HBA_FLAGS_PSCSI_MODE = 0x02, }; -/* struct se_lun->lun_status */ -enum transport_lun_status_table { - TRANSPORT_LUN_STATUS_FREE = 0, - TRANSPORT_LUN_STATUS_ACTIVE = 1, -}; - /* Special transport agnostic struct se_cmd->t_states */ enum transport_state_table { TRANSPORT_NO_STATE = 0, @@ -707,8 +701,6 @@ struct se_lun { u16 lun_rtpi; #define SE_LUN_LINK_MAGIC 0xffff7771 u32 lun_link_magic; - /* See transport_lun_status_table */ - enum transport_lun_status_table lun_status; u32 lun_access; u32 lun_flags; u32 unpacked_lun; -- cgit v1.2.3-70-g09d2 From 0a06d4309dc168dfa70cec3cf0cd9eb7fc15a2fd Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 10 May 2015 18:14:56 +0200 Subject: target: simplify backend driver registration Rewrite the backend driver registration based on what we did to the fabric drivers: introduce a read-only struct target_bakckend_ops that the driver registers, which is then instanciate as a struct target_backend by the core. This allows the ops vector to be smaller and allows us to mark it const. At the same time the registration function can set up the configfs attributes, avoiding the need to add additional boilerplate code for that to the drivers. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_configfs.c | 68 +++++++++++++------------ drivers/target/target_core_device.c | 6 +-- drivers/target/target_core_file.c | 16 ++---- drivers/target/target_core_hba.c | 96 ++++++++++++++++++++--------------- drivers/target/target_core_iblock.c | 18 ++----- drivers/target/target_core_internal.h | 16 ++++++ drivers/target/target_core_pscsi.c | 14 ++--- drivers/target/target_core_rd.c | 22 ++------ drivers/target/target_core_user.c | 11 ++-- include/target/target_core_backend.h | 22 ++------ include/target/target_core_base.h | 4 +- 11 files changed, 135 insertions(+), 158 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 4a31d4765390..57c099dd9da5 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -51,15 +51,26 @@ #include "target_core_xcopy.h" #define TB_CIT_SETUP(_name, _item_ops, _group_ops, _attrs) \ -static void target_core_setup_##_name##_cit(struct se_subsystem_api *sa) \ +static void target_core_setup_##_name##_cit(struct target_backend *tb) \ { \ - struct target_backend_cits *tbc = &sa->tb_cits; \ - struct config_item_type *cit = &tbc->tb_##_name##_cit; \ + struct config_item_type *cit = &tb->tb_##_name##_cit; \ \ cit->ct_item_ops = _item_ops; \ cit->ct_group_ops = _group_ops; \ cit->ct_attrs = _attrs; \ - cit->ct_owner = sa->owner; \ + cit->ct_owner = tb->ops->owner; \ + pr_debug("Setup generic %s\n", __stringify(_name)); \ +} + +#define TB_CIT_SETUP_DRV(_name, _item_ops, _group_ops) \ +static void target_core_setup_##_name##_cit(struct target_backend *tb) \ +{ \ + struct config_item_type *cit = &tb->tb_##_name##_cit; \ + \ + cit->ct_item_ops = _item_ops; \ + cit->ct_group_ops = _group_ops; \ + cit->ct_attrs = tb->ops->tb_##_name##_attrs; \ + cit->ct_owner = tb->ops->owner; \ pr_debug("Setup generic %s\n", __stringify(_name)); \ } @@ -469,7 +480,7 @@ static struct configfs_item_operations target_core_dev_attrib_ops = { .store_attribute = target_core_dev_attrib_attr_store, }; -TB_CIT_SETUP(dev_attrib, &target_core_dev_attrib_ops, NULL, NULL); +TB_CIT_SETUP_DRV(dev_attrib, &target_core_dev_attrib_ops, NULL); /* End functions for struct config_item_type tb_dev_attrib_cit */ @@ -1174,13 +1185,13 @@ TB_CIT_SETUP(dev_pr, &target_core_dev_pr_ops, NULL, target_core_dev_pr_attrs); static ssize_t target_core_show_dev_info(void *p, char *page) { struct se_device *dev = p; - struct se_subsystem_api *t = dev->transport; int bl = 0; ssize_t read_bytes = 0; transport_dump_dev_state(dev, page, &bl); read_bytes += bl; - read_bytes += t->show_configfs_dev_params(dev, page+read_bytes); + read_bytes += dev->transport->show_configfs_dev_params(dev, + page+read_bytes); return read_bytes; } @@ -1198,9 +1209,8 @@ static ssize_t target_core_store_dev_control( size_t count) { struct se_device *dev = p; - struct se_subsystem_api *t = dev->transport; - return t->set_configfs_dev_params(dev, page, count); + return dev->transport->set_configfs_dev_params(dev, page, count); } static struct target_core_configfs_attribute target_core_attr_dev_control = { @@ -2477,9 +2487,9 @@ static struct config_group *target_core_make_subdev( const char *name) { struct t10_alua_tg_pt_gp *tg_pt_gp; - struct se_subsystem_api *t; struct config_item *hba_ci = &group->cg_item; struct se_hba *hba = item_to_hba(hba_ci); + struct target_backend *tb = hba->backend; struct se_device *dev; struct config_group *dev_cg = NULL, *tg_pt_gp_cg = NULL; struct config_group *dev_stat_grp = NULL; @@ -2488,10 +2498,6 @@ static struct config_group *target_core_make_subdev( ret = mutex_lock_interruptible(&hba->hba_access_mutex); if (ret) return ERR_PTR(ret); - /* - * Locate the struct se_subsystem_api from parent's struct se_hba. - */ - t = hba->transport; dev = target_alloc_device(hba, name); if (!dev) @@ -2504,17 +2510,17 @@ static struct config_group *target_core_make_subdev( if (!dev_cg->default_groups) goto out_free_device; - config_group_init_type_name(dev_cg, name, &t->tb_cits.tb_dev_cit); + config_group_init_type_name(dev_cg, name, &tb->tb_dev_cit); config_group_init_type_name(&dev->dev_attrib.da_group, "attrib", - &t->tb_cits.tb_dev_attrib_cit); + &tb->tb_dev_attrib_cit); config_group_init_type_name(&dev->dev_pr_group, "pr", - &t->tb_cits.tb_dev_pr_cit); + &tb->tb_dev_pr_cit); config_group_init_type_name(&dev->t10_wwn.t10_wwn_group, "wwn", - &t->tb_cits.tb_dev_wwn_cit); + &tb->tb_dev_wwn_cit); config_group_init_type_name(&dev->t10_alua.alua_tg_pt_gps_group, - "alua", &t->tb_cits.tb_dev_alua_tg_pt_gps_cit); + "alua", &tb->tb_dev_alua_tg_pt_gps_cit); config_group_init_type_name(&dev->dev_stat_grps.stat_group, - "statistics", &t->tb_cits.tb_dev_stat_cit); + "statistics", &tb->tb_dev_stat_cit); dev_cg->default_groups[0] = &dev->dev_attrib.da_group; dev_cg->default_groups[1] = &dev->dev_pr_group; @@ -2644,7 +2650,7 @@ static ssize_t target_core_hba_show_attr_hba_info( char *page) { return sprintf(page, "HBA Index: %d plugin: %s version: %s\n", - hba->hba_id, hba->transport->name, + hba->hba_id, hba->backend->ops->name, TARGET_CORE_CONFIGFS_VERSION); } @@ -2664,11 +2670,10 @@ static ssize_t target_core_hba_show_attr_hba_mode(struct se_hba *hba, static ssize_t target_core_hba_store_attr_hba_mode(struct se_hba *hba, const char *page, size_t count) { - struct se_subsystem_api *transport = hba->transport; unsigned long mode_flag; int ret; - if (transport->pmode_enable_hba == NULL) + if (hba->backend->ops->pmode_enable_hba == NULL) return -EINVAL; ret = kstrtoul(page, 0, &mode_flag); @@ -2682,7 +2687,7 @@ static ssize_t target_core_hba_store_attr_hba_mode(struct se_hba *hba, return -EINVAL; } - ret = transport->pmode_enable_hba(hba, mode_flag); + ret = hba->backend->ops->pmode_enable_hba(hba, mode_flag); if (ret < 0) return -EINVAL; if (ret > 0) @@ -2808,16 +2813,15 @@ static struct config_item_type target_core_cit = { /* Stop functions for struct config_item_type target_core_hba_cit */ -void target_core_setup_sub_cits(struct se_subsystem_api *sa) +void target_setup_backend_cits(struct target_backend *tb) { - target_core_setup_dev_cit(sa); - target_core_setup_dev_attrib_cit(sa); - target_core_setup_dev_pr_cit(sa); - target_core_setup_dev_wwn_cit(sa); - target_core_setup_dev_alua_tg_pt_gps_cit(sa); - target_core_setup_dev_stat_cit(sa); + target_core_setup_dev_cit(tb); + target_core_setup_dev_attrib_cit(tb); + target_core_setup_dev_pr_cit(tb); + target_core_setup_dev_wwn_cit(tb); + target_core_setup_dev_alua_tg_pt_gps_cit(tb); + target_core_setup_dev_stat_cit(tb); } -EXPORT_SYMBOL(target_core_setup_sub_cits); static int __init target_core_init_configfs(void) { diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 47a73609e277..af906f1caaa7 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -1367,13 +1367,13 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name) struct se_device *dev; struct se_lun *xcopy_lun; - dev = hba->transport->alloc_device(hba, name); + dev = hba->backend->ops->alloc_device(hba, name); if (!dev) return NULL; dev->dev_link_magic = SE_DEV_LINK_MAGIC; dev->se_hba = hba; - dev->transport = hba->transport; + dev->transport = hba->backend->ops; dev->prot_length = sizeof(struct se_dif_v1_tuple); INIT_LIST_HEAD(&dev->dev_list); @@ -1571,7 +1571,7 @@ int core_dev_setup_virtual_lun0(void) goto out_free_hba; } - hba->transport->set_configfs_dev_params(dev, buf, sizeof(buf)); + hba->backend->ops->set_configfs_dev_params(dev, buf, sizeof(buf)); ret = target_configure_device(dev); if (ret) diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index e865885352da..7c5b1ef57d34 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -46,10 +46,6 @@ static inline struct fd_dev *FD_DEV(struct se_device *dev) return container_of(dev, struct fd_dev, dev); } -/* fd_attach_hba(): (Part of se_subsystem_api_t template) - * - * - */ static int fd_attach_hba(struct se_hba *hba, u32 host_id) { struct fd_host *fd_host; @@ -881,7 +877,7 @@ static struct configfs_attribute *fileio_backend_dev_attrs[] = { NULL, }; -static struct se_subsystem_api fileio_template = { +static const struct target_backend_ops fileio_ops = { .name = "fileio", .inquiry_prod = "FILEIO", .inquiry_rev = FD_VERSION, @@ -899,21 +895,17 @@ static struct se_subsystem_api fileio_template = { .init_prot = fd_init_prot, .format_prot = fd_format_prot, .free_prot = fd_free_prot, + .tb_dev_attrib_attrs = fileio_backend_dev_attrs, }; static int __init fileio_module_init(void) { - struct target_backend_cits *tbc = &fileio_template.tb_cits; - - target_core_setup_sub_cits(&fileio_template); - tbc->tb_dev_attrib_cit.ct_attrs = fileio_backend_dev_attrs; - - return transport_subsystem_register(&fileio_template); + return transport_backend_register(&fileio_ops); } static void __exit fileio_module_exit(void) { - transport_subsystem_release(&fileio_template); + target_backend_unregister(&fileio_ops); } MODULE_DESCRIPTION("TCM FILEIO subsystem plugin"); diff --git a/drivers/target/target_core_hba.c b/drivers/target/target_core_hba.c index e6e496ff9546..62ea4e8e70a8 100644 --- a/drivers/target/target_core_hba.c +++ b/drivers/target/target_core_hba.c @@ -39,63 +39,75 @@ #include "target_core_internal.h" -static LIST_HEAD(subsystem_list); -static DEFINE_MUTEX(subsystem_mutex); +static LIST_HEAD(backend_list); +static DEFINE_MUTEX(backend_mutex); static u32 hba_id_counter; static DEFINE_SPINLOCK(hba_lock); static LIST_HEAD(hba_list); -int transport_subsystem_register(struct se_subsystem_api *sub_api) -{ - struct se_subsystem_api *s; - - INIT_LIST_HEAD(&sub_api->sub_api_list); - mutex_lock(&subsystem_mutex); - list_for_each_entry(s, &subsystem_list, sub_api_list) { - if (!strcmp(s->name, sub_api->name)) { - pr_err("%p is already registered with" - " duplicate name %s, unable to process" - " request\n", s, s->name); - mutex_unlock(&subsystem_mutex); +int transport_backend_register(const struct target_backend_ops *ops) +{ + struct target_backend *tb, *old; + + tb = kzalloc(sizeof(*tb), GFP_KERNEL); + if (!tb) + return -ENOMEM; + tb->ops = ops; + + mutex_lock(&backend_mutex); + list_for_each_entry(old, &backend_list, list) { + if (!strcmp(old->ops->name, ops->name)) { + pr_err("backend %s already registered.\n", ops->name); + mutex_unlock(&backend_mutex); + kfree(tb); return -EEXIST; } } - list_add_tail(&sub_api->sub_api_list, &subsystem_list); - mutex_unlock(&subsystem_mutex); + target_setup_backend_cits(tb); + list_add_tail(&tb->list, &backend_list); + mutex_unlock(&backend_mutex); - pr_debug("TCM: Registered subsystem plugin: %s struct module:" - " %p\n", sub_api->name, sub_api->owner); + pr_debug("TCM: Registered subsystem plugin: %s struct module: %p\n", + ops->name, ops->owner); return 0; } -EXPORT_SYMBOL(transport_subsystem_register); +EXPORT_SYMBOL(transport_backend_register); -void transport_subsystem_release(struct se_subsystem_api *sub_api) +void target_backend_unregister(const struct target_backend_ops *ops) { - mutex_lock(&subsystem_mutex); - list_del(&sub_api->sub_api_list); - mutex_unlock(&subsystem_mutex); + struct target_backend *tb; + + mutex_lock(&backend_mutex); + list_for_each_entry(tb, &backend_list, list) { + if (tb->ops == ops) { + list_del(&tb->list); + kfree(tb); + break; + } + } + mutex_unlock(&backend_mutex); } -EXPORT_SYMBOL(transport_subsystem_release); +EXPORT_SYMBOL(target_backend_unregister); -static struct se_subsystem_api *core_get_backend(const char *sub_name) +static struct target_backend *core_get_backend(const char *name) { - struct se_subsystem_api *s; + struct target_backend *tb; - mutex_lock(&subsystem_mutex); - list_for_each_entry(s, &subsystem_list, sub_api_list) { - if (!strcmp(s->name, sub_name)) + mutex_lock(&backend_mutex); + list_for_each_entry(tb, &backend_list, list) { + if (!strcmp(tb->ops->name, name)) goto found; } - mutex_unlock(&subsystem_mutex); + mutex_unlock(&backend_mutex); return NULL; found: - if (s->owner && !try_module_get(s->owner)) - s = NULL; - mutex_unlock(&subsystem_mutex); - return s; + if (tb->ops->owner && !try_module_get(tb->ops->owner)) + tb = NULL; + mutex_unlock(&backend_mutex); + return tb; } struct se_hba * @@ -116,13 +128,13 @@ core_alloc_hba(const char *plugin_name, u32 plugin_dep_id, u32 hba_flags) hba->hba_index = scsi_get_new_index(SCSI_INST_INDEX); hba->hba_flags |= hba_flags; - hba->transport = core_get_backend(plugin_name); - if (!hba->transport) { + hba->backend = core_get_backend(plugin_name); + if (!hba->backend) { ret = -EINVAL; goto out_free_hba; } - ret = hba->transport->attach_hba(hba, plugin_dep_id); + ret = hba->backend->ops->attach_hba(hba, plugin_dep_id); if (ret < 0) goto out_module_put; @@ -137,8 +149,8 @@ core_alloc_hba(const char *plugin_name, u32 plugin_dep_id, u32 hba_flags) return hba; out_module_put: - module_put(hba->transport->owner); - hba->transport = NULL; + module_put(hba->backend->ops->owner); + hba->backend = NULL; out_free_hba: kfree(hba); return ERR_PTR(ret); @@ -149,7 +161,7 @@ core_delete_hba(struct se_hba *hba) { WARN_ON(hba->dev_count); - hba->transport->detach_hba(hba); + hba->backend->ops->detach_hba(hba); spin_lock(&hba_lock); list_del(&hba->hba_node); @@ -158,9 +170,9 @@ core_delete_hba(struct se_hba *hba) pr_debug("CORE_HBA[%d] - Detached HBA from Generic Target" " Core\n", hba->hba_id); - module_put(hba->transport->owner); + module_put(hba->backend->ops->owner); - hba->transport = NULL; + hba->backend = NULL; kfree(hba); return 0; } diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 8c965683789f..79f651fb98fb 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -54,12 +54,6 @@ static inline struct iblock_dev *IBLOCK_DEV(struct se_device *dev) } -static struct se_subsystem_api iblock_template; - -/* iblock_attach_hba(): (Part of se_subsystem_api_t template) - * - * - */ static int iblock_attach_hba(struct se_hba *hba, u32 host_id) { pr_debug("CORE_HBA[%d] - TCM iBlock HBA Driver %s on" @@ -899,7 +893,7 @@ static struct configfs_attribute *iblock_backend_dev_attrs[] = { NULL, }; -static struct se_subsystem_api iblock_template = { +static const struct target_backend_ops iblock_ops = { .name = "iblock", .inquiry_prod = "IBLOCK", .inquiry_rev = IBLOCK_VERSION, @@ -919,21 +913,17 @@ static struct se_subsystem_api iblock_template = { .get_io_min = iblock_get_io_min, .get_io_opt = iblock_get_io_opt, .get_write_cache = iblock_get_write_cache, + .tb_dev_attrib_attrs = iblock_backend_dev_attrs, }; static int __init iblock_module_init(void) { - struct target_backend_cits *tbc = &iblock_template.tb_cits; - - target_core_setup_sub_cits(&iblock_template); - tbc->tb_dev_attrib_cit.ct_attrs = iblock_backend_dev_attrs; - - return transport_subsystem_register(&iblock_template); + return transport_backend_register(&iblock_ops); } static void __exit iblock_module_exit(void) { - transport_subsystem_release(&iblock_template); + target_backend_unregister(&iblock_ops); } MODULE_DESCRIPTION("TCM IBLOCK subsystem plugin"); diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index ce80ca76f68b..01181aed67dc 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -1,6 +1,19 @@ #ifndef TARGET_CORE_INTERNAL_H #define TARGET_CORE_INTERNAL_H +struct target_backend { + struct list_head list; + + const struct target_backend_ops *ops; + + struct config_item_type tb_dev_cit; + struct config_item_type tb_dev_attrib_cit; + struct config_item_type tb_dev_pr_cit; + struct config_item_type tb_dev_wwn_cit; + struct config_item_type tb_dev_alua_tg_pt_gps_cit; + struct config_item_type tb_dev_stat_cit; +}; + /* target_core_alua.c */ extern struct t10_alua_lu_gp *default_lu_gp; @@ -40,6 +53,9 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name); int target_configure_device(struct se_device *dev); void target_free_device(struct se_device *); +/* target_core_configfs.c */ +void target_setup_backend_cits(struct target_backend *); + /* target_core_fabric_lib.c */ int target_get_pr_transport_id_len(struct se_node_acl *nacl, struct t10_pr_registration *pr_reg, int *format_code); diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 21db991b4465..2e3a0b004f9a 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -57,8 +57,6 @@ static inline struct pscsi_dev_virt *PSCSI_DEV(struct se_device *dev) return container_of(dev, struct pscsi_dev_virt, dev); } -static struct se_subsystem_api pscsi_template; - static sense_reason_t pscsi_execute_cmd(struct se_cmd *cmd); static void pscsi_req_done(struct request *, int); @@ -1141,7 +1139,7 @@ static struct configfs_attribute *pscsi_backend_dev_attrs[] = { NULL, }; -static struct se_subsystem_api pscsi_template = { +static const struct target_backend_ops pscsi_ops = { .name = "pscsi", .owner = THIS_MODULE, .transport_flags = TRANSPORT_FLAG_PASSTHROUGH, @@ -1157,21 +1155,17 @@ static struct se_subsystem_api pscsi_template = { .show_configfs_dev_params = pscsi_show_configfs_dev_params, .get_device_type = pscsi_get_device_type, .get_blocks = pscsi_get_blocks, + .tb_dev_attrib_attrs = pscsi_backend_dev_attrs, }; static int __init pscsi_module_init(void) { - struct target_backend_cits *tbc = &pscsi_template.tb_cits; - - target_core_setup_sub_cits(&pscsi_template); - tbc->tb_dev_attrib_cit.ct_attrs = pscsi_backend_dev_attrs; - - return transport_subsystem_register(&pscsi_template); + return transport_backend_register(&pscsi_ops); } static void __exit pscsi_module_exit(void) { - transport_subsystem_release(&pscsi_template); + target_backend_unregister(&pscsi_ops); } MODULE_DESCRIPTION("TCM PSCSI subsystem plugin"); diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c index 55315fd0f5d3..cf443a8a3cbe 100644 --- a/drivers/target/target_core_rd.c +++ b/drivers/target/target_core_rd.c @@ -43,10 +43,6 @@ static inline struct rd_dev *RD_DEV(struct se_device *dev) return container_of(dev, struct rd_dev, dev); } -/* rd_attach_hba(): (Part of se_subsystem_api_t template) - * - * - */ static int rd_attach_hba(struct se_hba *hba, u32 host_id) { struct rd_host *rd_host; @@ -735,7 +731,7 @@ static struct configfs_attribute *rd_mcp_backend_dev_attrs[] = { NULL, }; -static struct se_subsystem_api rd_mcp_template = { +static const struct target_backend_ops rd_mcp_ops = { .name = "rd_mcp", .inquiry_prod = "RAMDISK-MCP", .inquiry_rev = RD_MCP_VERSION, @@ -751,25 +747,15 @@ static struct se_subsystem_api rd_mcp_template = { .get_blocks = rd_get_blocks, .init_prot = rd_init_prot, .free_prot = rd_free_prot, + .tb_dev_attrib_attrs = rd_mcp_backend_dev_attrs, }; int __init rd_module_init(void) { - struct target_backend_cits *tbc = &rd_mcp_template.tb_cits; - int ret; - - target_core_setup_sub_cits(&rd_mcp_template); - tbc->tb_dev_attrib_cit.ct_attrs = rd_mcp_backend_dev_attrs; - - ret = transport_subsystem_register(&rd_mcp_template); - if (ret < 0) { - return ret; - } - - return 0; + return transport_backend_register(&rd_mcp_ops); } void rd_module_exit(void) { - transport_subsystem_release(&rd_mcp_template); + target_backend_unregister(&rd_mcp_ops); } diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 60330e00f59d..fb67e313dc4f 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1115,7 +1115,7 @@ static struct configfs_attribute *tcmu_backend_dev_attrs[] = { NULL, }; -static struct se_subsystem_api tcmu_template = { +static const struct target_backend_ops tcmu_ops = { .name = "user", .inquiry_prod = "USER", .inquiry_rev = TCMU_VERSION, @@ -1131,11 +1131,11 @@ static struct se_subsystem_api tcmu_template = { .show_configfs_dev_params = tcmu_show_configfs_dev_params, .get_device_type = sbc_get_device_type, .get_blocks = tcmu_get_blocks, + .tb_dev_attrib_attrs = tcmu_backend_dev_attrs, }; static int __init tcmu_module_init(void) { - struct target_backend_cits *tbc = &tcmu_template.tb_cits; int ret; BUILD_BUG_ON((sizeof(struct tcmu_cmd_entry) % TCMU_OP_ALIGN_SIZE) != 0); @@ -1158,10 +1158,7 @@ static int __init tcmu_module_init(void) goto out_unreg_device; } - target_core_setup_sub_cits(&tcmu_template); - tbc->tb_dev_attrib_cit.ct_attrs = tcmu_backend_dev_attrs; - - ret = transport_subsystem_register(&tcmu_template); + ret = transport_backend_register(&tcmu_ops); if (ret) goto out_unreg_genl; @@ -1179,7 +1176,7 @@ out_free_cache: static void __exit tcmu_module_exit(void) { - transport_subsystem_release(&tcmu_template); + target_backend_unregister(&tcmu_ops); genl_unregister_family(&tcmu_genl_family); root_device_unregister(tcmu_root_device); kmem_cache_destroy(tcmu_cmd_cache); diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index 80d9e486e33e..514b52019380 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -3,18 +3,7 @@ #define TRANSPORT_FLAG_PASSTHROUGH 1 -struct target_backend_cits { - struct config_item_type tb_dev_cit; - struct config_item_type tb_dev_attrib_cit; - struct config_item_type tb_dev_pr_cit; - struct config_item_type tb_dev_wwn_cit; - struct config_item_type tb_dev_alua_tg_pt_gps_cit; - struct config_item_type tb_dev_stat_cit; -}; - -struct se_subsystem_api { - struct list_head sub_api_list; - +struct target_backend_ops { char name[16]; char inquiry_prod[16]; char inquiry_rev[4]; @@ -52,7 +41,7 @@ struct se_subsystem_api { int (*format_prot)(struct se_device *); void (*free_prot)(struct se_device *); - struct target_backend_cits tb_cits; + struct configfs_attribute **tb_dev_attrib_attrs; }; struct sbc_ops { @@ -64,8 +53,8 @@ struct sbc_ops { sense_reason_t (*execute_unmap)(struct se_cmd *cmd); }; -int transport_subsystem_register(struct se_subsystem_api *); -void transport_subsystem_release(struct se_subsystem_api *); +int transport_backend_register(const struct target_backend_ops *); +void target_backend_unregister(const struct target_backend_ops *); void target_complete_cmd(struct se_cmd *, u8); void target_complete_cmd_with_length(struct se_cmd *, u8, int); @@ -103,9 +92,6 @@ sense_reason_t transport_generic_map_mem_to_cmd(struct se_cmd *, bool target_lun_is_rdonly(struct se_cmd *); -/* From target_core_configfs.c to setup default backend config_item_types */ -void target_core_setup_sub_cits(struct se_subsystem_api *); - /* attribute helpers from target_core_device.c for backend drivers */ bool se_dev_check_wce(struct se_device *); int se_dev_set_max_unmap_lba_count(struct se_device *, u32); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 78ed2a83838c..03e2ee8f8337 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -797,7 +797,7 @@ struct se_device { #define SE_UDEV_PATH_LEN 512 /* must be less than PAGE_SIZE */ unsigned char udev_path[SE_UDEV_PATH_LEN]; /* Pointer to template of function pointers for transport */ - struct se_subsystem_api *transport; + const struct target_backend_ops *transport; /* Linked list for struct se_hba struct se_device list */ struct list_head dev_list; struct se_lun xcopy_lun; @@ -819,7 +819,7 @@ struct se_hba { spinlock_t device_lock; struct config_group hba_group; struct mutex hba_access_mutex; - struct se_subsystem_api *transport; + struct target_backend *backend; }; struct scsi_port_stats { -- cgit v1.2.3-70-g09d2 From 5873c4d157400ade4052e9d7b6259fa592e1ddbf Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 10 May 2015 18:14:57 +0200 Subject: target: consolidate backend attribute implementations Provide a common sets of dev_attrib attributes for all devices using the generic SPC/SBC parsers, and a second one with the minimal required read-only attributes for passthrough devices. The later is only used by pscsi for now, but will be wired up for the full-passthrough TCMU use case as well. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_configfs.c | 169 ++++++++++++++++++++++++++ drivers/target/target_core_file.c | 38 +----- drivers/target/target_core_iblock.c | 38 +----- drivers/target/target_core_pscsi.c | 23 +--- drivers/target/target_core_rd.c | 38 +----- drivers/target/target_core_user.c | 23 +--- include/target/target_core_backend.h | 3 + include/target/target_core_backend_configfs.h | 118 ------------------ 8 files changed, 177 insertions(+), 273 deletions(-) delete mode 100644 include/target/target_core_backend_configfs.h (limited to 'drivers') diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 57c099dd9da5..dbf91f02ee5c 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -471,10 +471,179 @@ EXPORT_SYMBOL(target_unregister_template); //############################################################################*/ /* Start functions for struct config_item_type tb_dev_attrib_cit */ +#define DEF_TB_DEV_ATTRIB_SHOW(_backend, _name) \ +static ssize_t _backend##_dev_show_attr_##_name( \ + struct se_dev_attrib *da, \ + char *page) \ +{ \ + return snprintf(page, PAGE_SIZE, "%u\n", \ + (u32)da->da_dev->dev_attrib._name); \ +} + +#define DEF_TB_DEV_ATTRIB_STORE(_backend, _name) \ +static ssize_t _backend##_dev_store_attr_##_name( \ + struct se_dev_attrib *da, \ + const char *page, \ + size_t count) \ +{ \ + unsigned long val; \ + int ret; \ + \ + ret = kstrtoul(page, 0, &val); \ + if (ret < 0) { \ + pr_err("kstrtoul() failed with ret: %d\n", ret); \ + return -EINVAL; \ + } \ + ret = se_dev_set_##_name(da->da_dev, (u32)val); \ + \ + return (!ret) ? count : -EINVAL; \ +} + +#define DEF_TB_DEV_ATTRIB(_backend, _name) \ +DEF_TB_DEV_ATTRIB_SHOW(_backend, _name); \ +DEF_TB_DEV_ATTRIB_STORE(_backend, _name); + +#define DEF_TB_DEV_ATTRIB_RO(_backend, name) \ +DEF_TB_DEV_ATTRIB_SHOW(_backend, name); + +CONFIGFS_EATTR_STRUCT(target_backend_dev_attrib, se_dev_attrib); +#define TB_DEV_ATTR(_backend, _name, _mode) \ +static struct target_backend_dev_attrib_attribute _backend##_dev_attrib_##_name = \ + __CONFIGFS_EATTR(_name, _mode, \ + _backend##_dev_show_attr_##_name, \ + _backend##_dev_store_attr_##_name); + +#define TB_DEV_ATTR_RO(_backend, _name) \ +static struct target_backend_dev_attrib_attribute _backend##_dev_attrib_##_name = \ + __CONFIGFS_EATTR_RO(_name, \ + _backend##_dev_show_attr_##_name); + +DEF_TB_DEV_ATTRIB(target_core, emulate_model_alias); +DEF_TB_DEV_ATTRIB(target_core, emulate_dpo); +DEF_TB_DEV_ATTRIB(target_core, emulate_fua_write); +DEF_TB_DEV_ATTRIB(target_core, emulate_fua_read); +DEF_TB_DEV_ATTRIB(target_core, emulate_write_cache); +DEF_TB_DEV_ATTRIB(target_core, emulate_ua_intlck_ctrl); +DEF_TB_DEV_ATTRIB(target_core, emulate_tas); +DEF_TB_DEV_ATTRIB(target_core, emulate_tpu); +DEF_TB_DEV_ATTRIB(target_core, emulate_tpws); +DEF_TB_DEV_ATTRIB(target_core, emulate_caw); +DEF_TB_DEV_ATTRIB(target_core, emulate_3pc); +DEF_TB_DEV_ATTRIB(target_core, pi_prot_type); +DEF_TB_DEV_ATTRIB_RO(target_core, hw_pi_prot_type); +DEF_TB_DEV_ATTRIB(target_core, pi_prot_format); +DEF_TB_DEV_ATTRIB(target_core, enforce_pr_isids); +DEF_TB_DEV_ATTRIB(target_core, is_nonrot); +DEF_TB_DEV_ATTRIB(target_core, emulate_rest_reord); +DEF_TB_DEV_ATTRIB(target_core, force_pr_aptpl); +DEF_TB_DEV_ATTRIB_RO(target_core, hw_block_size); +DEF_TB_DEV_ATTRIB(target_core, block_size); +DEF_TB_DEV_ATTRIB_RO(target_core, hw_max_sectors); +DEF_TB_DEV_ATTRIB(target_core, optimal_sectors); +DEF_TB_DEV_ATTRIB_RO(target_core, hw_queue_depth); +DEF_TB_DEV_ATTRIB(target_core, queue_depth); +DEF_TB_DEV_ATTRIB(target_core, max_unmap_lba_count); +DEF_TB_DEV_ATTRIB(target_core, max_unmap_block_desc_count); +DEF_TB_DEV_ATTRIB(target_core, unmap_granularity); +DEF_TB_DEV_ATTRIB(target_core, unmap_granularity_alignment); +DEF_TB_DEV_ATTRIB(target_core, max_write_same_len); + +TB_DEV_ATTR(target_core, emulate_model_alias, S_IRUGO | S_IWUSR); +TB_DEV_ATTR(target_core, emulate_dpo, S_IRUGO | S_IWUSR); +TB_DEV_ATTR(target_core, emulate_fua_write, S_IRUGO | S_IWUSR); +TB_DEV_ATTR(target_core, emulate_fua_read, S_IRUGO | S_IWUSR); +TB_DEV_ATTR(target_core, emulate_write_cache, S_IRUGO | S_IWUSR); +TB_DEV_ATTR(target_core, emulate_ua_intlck_ctrl, S_IRUGO | S_IWUSR); +TB_DEV_ATTR(target_core, emulate_tas, S_IRUGO | S_IWUSR); +TB_DEV_ATTR(target_core, emulate_tpu, S_IRUGO | S_IWUSR); +TB_DEV_ATTR(target_core, emulate_tpws, S_IRUGO | S_IWUSR); +TB_DEV_ATTR(target_core, emulate_caw, S_IRUGO | S_IWUSR); +TB_DEV_ATTR(target_core, emulate_3pc, S_IRUGO | S_IWUSR); +TB_DEV_ATTR(target_core, pi_prot_type, S_IRUGO | S_IWUSR); +TB_DEV_ATTR_RO(target_core, hw_pi_prot_type); +TB_DEV_ATTR(target_core, pi_prot_format, S_IRUGO | S_IWUSR); +TB_DEV_ATTR(target_core, enforce_pr_isids, S_IRUGO | S_IWUSR); +TB_DEV_ATTR(target_core, is_nonrot, S_IRUGO | S_IWUSR); +TB_DEV_ATTR(target_core, emulate_rest_reord, S_IRUGO | S_IWUSR); +TB_DEV_ATTR(target_core, force_pr_aptpl, S_IRUGO | S_IWUSR) +TB_DEV_ATTR_RO(target_core, hw_block_size); +TB_DEV_ATTR(target_core, block_size, S_IRUGO | S_IWUSR) +TB_DEV_ATTR_RO(target_core, hw_max_sectors); +TB_DEV_ATTR(target_core, optimal_sectors, S_IRUGO | S_IWUSR); +TB_DEV_ATTR_RO(target_core, hw_queue_depth); +TB_DEV_ATTR(target_core, queue_depth, S_IRUGO | S_IWUSR); +TB_DEV_ATTR(target_core, max_unmap_lba_count, S_IRUGO | S_IWUSR); +TB_DEV_ATTR(target_core, max_unmap_block_desc_count, S_IRUGO | S_IWUSR); +TB_DEV_ATTR(target_core, unmap_granularity, S_IRUGO | S_IWUSR); +TB_DEV_ATTR(target_core, unmap_granularity_alignment, S_IRUGO | S_IWUSR); +TB_DEV_ATTR(target_core, max_write_same_len, S_IRUGO | S_IWUSR); CONFIGFS_EATTR_STRUCT(target_core_dev_attrib, se_dev_attrib); CONFIGFS_EATTR_OPS(target_core_dev_attrib, se_dev_attrib, da_group); +/* + * dev_attrib attributes for devices using the target core SBC/SPC + * interpreter. Any backend using spc_parse_cdb should be using + * these. + */ +struct configfs_attribute *sbc_attrib_attrs[] = { + &target_core_dev_attrib_emulate_model_alias.attr, + &target_core_dev_attrib_emulate_dpo.attr, + &target_core_dev_attrib_emulate_fua_write.attr, + &target_core_dev_attrib_emulate_fua_read.attr, + &target_core_dev_attrib_emulate_write_cache.attr, + &target_core_dev_attrib_emulate_ua_intlck_ctrl.attr, + &target_core_dev_attrib_emulate_tas.attr, + &target_core_dev_attrib_emulate_tpu.attr, + &target_core_dev_attrib_emulate_tpws.attr, + &target_core_dev_attrib_emulate_caw.attr, + &target_core_dev_attrib_emulate_3pc.attr, + &target_core_dev_attrib_pi_prot_type.attr, + &target_core_dev_attrib_hw_pi_prot_type.attr, + &target_core_dev_attrib_pi_prot_format.attr, + &target_core_dev_attrib_enforce_pr_isids.attr, + &target_core_dev_attrib_is_nonrot.attr, + &target_core_dev_attrib_emulate_rest_reord.attr, + &target_core_dev_attrib_force_pr_aptpl.attr, + &target_core_dev_attrib_hw_block_size.attr, + &target_core_dev_attrib_block_size.attr, + &target_core_dev_attrib_hw_max_sectors.attr, + &target_core_dev_attrib_optimal_sectors.attr, + &target_core_dev_attrib_hw_queue_depth.attr, + &target_core_dev_attrib_queue_depth.attr, + &target_core_dev_attrib_max_unmap_lba_count.attr, + &target_core_dev_attrib_max_unmap_block_desc_count.attr, + &target_core_dev_attrib_unmap_granularity.attr, + &target_core_dev_attrib_unmap_granularity_alignment.attr, + &target_core_dev_attrib_max_write_same_len.attr, + NULL, +}; +EXPORT_SYMBOL(sbc_attrib_attrs); + +DEF_TB_DEV_ATTRIB_RO(target_pt, hw_pi_prot_type); +DEF_TB_DEV_ATTRIB_RO(target_pt, hw_block_size); +DEF_TB_DEV_ATTRIB_RO(target_pt, hw_max_sectors); +DEF_TB_DEV_ATTRIB_RO(target_pt, hw_queue_depth); + +TB_DEV_ATTR_RO(target_pt, hw_pi_prot_type); +TB_DEV_ATTR_RO(target_pt, hw_block_size); +TB_DEV_ATTR_RO(target_pt, hw_max_sectors); +TB_DEV_ATTR_RO(target_pt, hw_queue_depth); + +/* + * Minimal dev_attrib attributes for devices passing through CDBs. + * In this case we only provide a few read-only attributes for + * backwards compatibility. + */ +struct configfs_attribute *passthrough_attrib_attrs[] = { + &target_pt_dev_attrib_hw_pi_prot_type.attr, + &target_pt_dev_attrib_hw_block_size.attr, + &target_pt_dev_attrib_hw_max_sectors.attr, + &target_pt_dev_attrib_hw_queue_depth.attr, + NULL, +}; +EXPORT_SYMBOL(passthrough_attrib_attrs); + static struct configfs_item_operations target_core_dev_attrib_ops = { .show_attribute = target_core_dev_attrib_attr_show, .store_attribute = target_core_dev_attrib_attr_store, diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index 7c5b1ef57d34..948b61f59a55 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -37,7 +37,6 @@ #include #include -#include #include "target_core_file.h" @@ -842,41 +841,6 @@ fd_parse_cdb(struct se_cmd *cmd) return sbc_parse_cdb(cmd, &fd_sbc_ops); } -DEF_TB_DEFAULT_ATTRIBS(fileio); - -static struct configfs_attribute *fileio_backend_dev_attrs[] = { - &fileio_dev_attrib_emulate_model_alias.attr, - &fileio_dev_attrib_emulate_dpo.attr, - &fileio_dev_attrib_emulate_fua_write.attr, - &fileio_dev_attrib_emulate_fua_read.attr, - &fileio_dev_attrib_emulate_write_cache.attr, - &fileio_dev_attrib_emulate_ua_intlck_ctrl.attr, - &fileio_dev_attrib_emulate_tas.attr, - &fileio_dev_attrib_emulate_tpu.attr, - &fileio_dev_attrib_emulate_tpws.attr, - &fileio_dev_attrib_emulate_caw.attr, - &fileio_dev_attrib_emulate_3pc.attr, - &fileio_dev_attrib_pi_prot_type.attr, - &fileio_dev_attrib_hw_pi_prot_type.attr, - &fileio_dev_attrib_pi_prot_format.attr, - &fileio_dev_attrib_enforce_pr_isids.attr, - &fileio_dev_attrib_is_nonrot.attr, - &fileio_dev_attrib_emulate_rest_reord.attr, - &fileio_dev_attrib_force_pr_aptpl.attr, - &fileio_dev_attrib_hw_block_size.attr, - &fileio_dev_attrib_block_size.attr, - &fileio_dev_attrib_hw_max_sectors.attr, - &fileio_dev_attrib_optimal_sectors.attr, - &fileio_dev_attrib_hw_queue_depth.attr, - &fileio_dev_attrib_queue_depth.attr, - &fileio_dev_attrib_max_unmap_lba_count.attr, - &fileio_dev_attrib_max_unmap_block_desc_count.attr, - &fileio_dev_attrib_unmap_granularity.attr, - &fileio_dev_attrib_unmap_granularity_alignment.attr, - &fileio_dev_attrib_max_write_same_len.attr, - NULL, -}; - static const struct target_backend_ops fileio_ops = { .name = "fileio", .inquiry_prod = "FILEIO", @@ -895,7 +859,7 @@ static const struct target_backend_ops fileio_ops = { .init_prot = fd_init_prot, .format_prot = fd_format_prot, .free_prot = fd_free_prot, - .tb_dev_attrib_attrs = fileio_backend_dev_attrs, + .tb_dev_attrib_attrs = sbc_attrib_attrs, }; static int __init fileio_module_init(void) diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 79f651fb98fb..6d4738252564 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -41,7 +41,6 @@ #include #include -#include #include "target_core_iblock.h" @@ -858,41 +857,6 @@ static bool iblock_get_write_cache(struct se_device *dev) return q->flush_flags & REQ_FLUSH; } -DEF_TB_DEFAULT_ATTRIBS(iblock); - -static struct configfs_attribute *iblock_backend_dev_attrs[] = { - &iblock_dev_attrib_emulate_model_alias.attr, - &iblock_dev_attrib_emulate_dpo.attr, - &iblock_dev_attrib_emulate_fua_write.attr, - &iblock_dev_attrib_emulate_fua_read.attr, - &iblock_dev_attrib_emulate_write_cache.attr, - &iblock_dev_attrib_emulate_ua_intlck_ctrl.attr, - &iblock_dev_attrib_emulate_tas.attr, - &iblock_dev_attrib_emulate_tpu.attr, - &iblock_dev_attrib_emulate_tpws.attr, - &iblock_dev_attrib_emulate_caw.attr, - &iblock_dev_attrib_emulate_3pc.attr, - &iblock_dev_attrib_pi_prot_type.attr, - &iblock_dev_attrib_hw_pi_prot_type.attr, - &iblock_dev_attrib_pi_prot_format.attr, - &iblock_dev_attrib_enforce_pr_isids.attr, - &iblock_dev_attrib_is_nonrot.attr, - &iblock_dev_attrib_emulate_rest_reord.attr, - &iblock_dev_attrib_force_pr_aptpl.attr, - &iblock_dev_attrib_hw_block_size.attr, - &iblock_dev_attrib_block_size.attr, - &iblock_dev_attrib_hw_max_sectors.attr, - &iblock_dev_attrib_optimal_sectors.attr, - &iblock_dev_attrib_hw_queue_depth.attr, - &iblock_dev_attrib_queue_depth.attr, - &iblock_dev_attrib_max_unmap_lba_count.attr, - &iblock_dev_attrib_max_unmap_block_desc_count.attr, - &iblock_dev_attrib_unmap_granularity.attr, - &iblock_dev_attrib_unmap_granularity_alignment.attr, - &iblock_dev_attrib_max_write_same_len.attr, - NULL, -}; - static const struct target_backend_ops iblock_ops = { .name = "iblock", .inquiry_prod = "IBLOCK", @@ -913,7 +877,7 @@ static const struct target_backend_ops iblock_ops = { .get_io_min = iblock_get_io_min, .get_io_opt = iblock_get_io_opt, .get_write_cache = iblock_get_write_cache, - .tb_dev_attrib_attrs = iblock_backend_dev_attrs, + .tb_dev_attrib_attrs = sbc_attrib_attrs, }; static int __init iblock_module_init(void) diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 2e3a0b004f9a..afb87a8d5668 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -44,7 +44,6 @@ #include #include -#include #include "target_core_alua.h" #include "target_core_internal.h" @@ -1119,26 +1118,6 @@ static void pscsi_req_done(struct request *req, int uptodate) kfree(pt); } -DEF_TB_DEV_ATTRIB_RO(pscsi, hw_pi_prot_type); -TB_DEV_ATTR_RO(pscsi, hw_pi_prot_type); - -DEF_TB_DEV_ATTRIB_RO(pscsi, hw_block_size); -TB_DEV_ATTR_RO(pscsi, hw_block_size); - -DEF_TB_DEV_ATTRIB_RO(pscsi, hw_max_sectors); -TB_DEV_ATTR_RO(pscsi, hw_max_sectors); - -DEF_TB_DEV_ATTRIB_RO(pscsi, hw_queue_depth); -TB_DEV_ATTR_RO(pscsi, hw_queue_depth); - -static struct configfs_attribute *pscsi_backend_dev_attrs[] = { - &pscsi_dev_attrib_hw_pi_prot_type.attr, - &pscsi_dev_attrib_hw_block_size.attr, - &pscsi_dev_attrib_hw_max_sectors.attr, - &pscsi_dev_attrib_hw_queue_depth.attr, - NULL, -}; - static const struct target_backend_ops pscsi_ops = { .name = "pscsi", .owner = THIS_MODULE, @@ -1155,7 +1134,7 @@ static const struct target_backend_ops pscsi_ops = { .show_configfs_dev_params = pscsi_show_configfs_dev_params, .get_device_type = pscsi_get_device_type, .get_blocks = pscsi_get_blocks, - .tb_dev_attrib_attrs = pscsi_backend_dev_attrs, + .tb_dev_attrib_attrs = passthrough_attrib_attrs, }; static int __init pscsi_module_init(void) diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c index cf443a8a3cbe..55dd73e7f213 100644 --- a/drivers/target/target_core_rd.c +++ b/drivers/target/target_core_rd.c @@ -34,7 +34,6 @@ #include #include -#include #include "target_core_rd.h" @@ -696,41 +695,6 @@ rd_parse_cdb(struct se_cmd *cmd) return sbc_parse_cdb(cmd, &rd_sbc_ops); } -DEF_TB_DEFAULT_ATTRIBS(rd_mcp); - -static struct configfs_attribute *rd_mcp_backend_dev_attrs[] = { - &rd_mcp_dev_attrib_emulate_model_alias.attr, - &rd_mcp_dev_attrib_emulate_dpo.attr, - &rd_mcp_dev_attrib_emulate_fua_write.attr, - &rd_mcp_dev_attrib_emulate_fua_read.attr, - &rd_mcp_dev_attrib_emulate_write_cache.attr, - &rd_mcp_dev_attrib_emulate_ua_intlck_ctrl.attr, - &rd_mcp_dev_attrib_emulate_tas.attr, - &rd_mcp_dev_attrib_emulate_tpu.attr, - &rd_mcp_dev_attrib_emulate_tpws.attr, - &rd_mcp_dev_attrib_emulate_caw.attr, - &rd_mcp_dev_attrib_emulate_3pc.attr, - &rd_mcp_dev_attrib_pi_prot_type.attr, - &rd_mcp_dev_attrib_hw_pi_prot_type.attr, - &rd_mcp_dev_attrib_pi_prot_format.attr, - &rd_mcp_dev_attrib_enforce_pr_isids.attr, - &rd_mcp_dev_attrib_is_nonrot.attr, - &rd_mcp_dev_attrib_emulate_rest_reord.attr, - &rd_mcp_dev_attrib_force_pr_aptpl.attr, - &rd_mcp_dev_attrib_hw_block_size.attr, - &rd_mcp_dev_attrib_block_size.attr, - &rd_mcp_dev_attrib_hw_max_sectors.attr, - &rd_mcp_dev_attrib_optimal_sectors.attr, - &rd_mcp_dev_attrib_hw_queue_depth.attr, - &rd_mcp_dev_attrib_queue_depth.attr, - &rd_mcp_dev_attrib_max_unmap_lba_count.attr, - &rd_mcp_dev_attrib_max_unmap_block_desc_count.attr, - &rd_mcp_dev_attrib_unmap_granularity.attr, - &rd_mcp_dev_attrib_unmap_granularity_alignment.attr, - &rd_mcp_dev_attrib_max_write_same_len.attr, - NULL, -}; - static const struct target_backend_ops rd_mcp_ops = { .name = "rd_mcp", .inquiry_prod = "RAMDISK-MCP", @@ -747,7 +711,7 @@ static const struct target_backend_ops rd_mcp_ops = { .get_blocks = rd_get_blocks, .init_prot = rd_init_prot, .free_prot = rd_free_prot, - .tb_dev_attrib_attrs = rd_mcp_backend_dev_attrs, + .tb_dev_attrib_attrs = sbc_attrib_attrs, }; int __init rd_module_init(void) diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index fb67e313dc4f..aebaad55e23f 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -29,7 +29,6 @@ #include #include #include -#include #include @@ -1095,26 +1094,6 @@ tcmu_parse_cdb(struct se_cmd *cmd) return passthrough_parse_cdb(cmd, tcmu_pass_op); } -DEF_TB_DEV_ATTRIB_RO(tcmu, hw_pi_prot_type); -TB_DEV_ATTR_RO(tcmu, hw_pi_prot_type); - -DEF_TB_DEV_ATTRIB_RO(tcmu, hw_block_size); -TB_DEV_ATTR_RO(tcmu, hw_block_size); - -DEF_TB_DEV_ATTRIB_RO(tcmu, hw_max_sectors); -TB_DEV_ATTR_RO(tcmu, hw_max_sectors); - -DEF_TB_DEV_ATTRIB_RO(tcmu, hw_queue_depth); -TB_DEV_ATTR_RO(tcmu, hw_queue_depth); - -static struct configfs_attribute *tcmu_backend_dev_attrs[] = { - &tcmu_dev_attrib_hw_pi_prot_type.attr, - &tcmu_dev_attrib_hw_block_size.attr, - &tcmu_dev_attrib_hw_max_sectors.attr, - &tcmu_dev_attrib_hw_queue_depth.attr, - NULL, -}; - static const struct target_backend_ops tcmu_ops = { .name = "user", .inquiry_prod = "USER", @@ -1131,7 +1110,7 @@ static const struct target_backend_ops tcmu_ops = { .show_configfs_dev_params = tcmu_show_configfs_dev_params, .get_device_type = sbc_get_device_type, .get_blocks = tcmu_get_blocks, - .tb_dev_attrib_attrs = tcmu_backend_dev_attrs, + .tb_dev_attrib_attrs = passthrough_attrib_attrs, }; static int __init tcmu_module_init(void) diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index 514b52019380..2d5610516494 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -82,6 +82,9 @@ int transport_set_vpd_assoc(struct t10_vpd *, unsigned char *); int transport_set_vpd_ident_type(struct t10_vpd *, unsigned char *); int transport_set_vpd_ident(struct t10_vpd *, unsigned char *); +extern struct configfs_attribute *sbc_attrib_attrs[]; +extern struct configfs_attribute *passthrough_attrib_attrs[]; + /* core helpers also used by command snooping in pscsi */ void *transport_kmap_data_sg(struct se_cmd *); void transport_kunmap_data_sg(struct se_cmd *); diff --git a/include/target/target_core_backend_configfs.h b/include/target/target_core_backend_configfs.h deleted file mode 100644 index 186f7a923570..000000000000 --- a/include/target/target_core_backend_configfs.h +++ /dev/null @@ -1,118 +0,0 @@ -#ifndef TARGET_CORE_BACKEND_CONFIGFS_H -#define TARGET_CORE_BACKEND_CONFIGFS_H - -#include - -#define DEF_TB_DEV_ATTRIB_SHOW(_backend, _name) \ -static ssize_t _backend##_dev_show_attr_##_name( \ - struct se_dev_attrib *da, \ - char *page) \ -{ \ - return snprintf(page, PAGE_SIZE, "%u\n", \ - (u32)da->da_dev->dev_attrib._name); \ -} - -#define DEF_TB_DEV_ATTRIB_STORE(_backend, _name) \ -static ssize_t _backend##_dev_store_attr_##_name( \ - struct se_dev_attrib *da, \ - const char *page, \ - size_t count) \ -{ \ - unsigned long val; \ - int ret; \ - \ - ret = kstrtoul(page, 0, &val); \ - if (ret < 0) { \ - pr_err("kstrtoul() failed with ret: %d\n", ret); \ - return -EINVAL; \ - } \ - ret = se_dev_set_##_name(da->da_dev, (u32)val); \ - \ - return (!ret) ? count : -EINVAL; \ -} - -#define DEF_TB_DEV_ATTRIB(_backend, _name) \ -DEF_TB_DEV_ATTRIB_SHOW(_backend, _name); \ -DEF_TB_DEV_ATTRIB_STORE(_backend, _name); - -#define DEF_TB_DEV_ATTRIB_RO(_backend, name) \ -DEF_TB_DEV_ATTRIB_SHOW(_backend, name); - -CONFIGFS_EATTR_STRUCT(target_backend_dev_attrib, se_dev_attrib); -#define TB_DEV_ATTR(_backend, _name, _mode) \ -static struct target_backend_dev_attrib_attribute _backend##_dev_attrib_##_name = \ - __CONFIGFS_EATTR(_name, _mode, \ - _backend##_dev_show_attr_##_name, \ - _backend##_dev_store_attr_##_name); - -#define TB_DEV_ATTR_RO(_backend, _name) \ -static struct target_backend_dev_attrib_attribute _backend##_dev_attrib_##_name = \ - __CONFIGFS_EATTR_RO(_name, \ - _backend##_dev_show_attr_##_name); - -/* - * Default list of target backend device attributes as defined by - * struct se_dev_attrib - */ - -#define DEF_TB_DEFAULT_ATTRIBS(_backend) \ - DEF_TB_DEV_ATTRIB(_backend, emulate_model_alias); \ - TB_DEV_ATTR(_backend, emulate_model_alias, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB(_backend, emulate_dpo); \ - TB_DEV_ATTR(_backend, emulate_dpo, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB(_backend, emulate_fua_write); \ - TB_DEV_ATTR(_backend, emulate_fua_write, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB(_backend, emulate_fua_read); \ - TB_DEV_ATTR(_backend, emulate_fua_read, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB(_backend, emulate_write_cache); \ - TB_DEV_ATTR(_backend, emulate_write_cache, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB(_backend, emulate_ua_intlck_ctrl); \ - TB_DEV_ATTR(_backend, emulate_ua_intlck_ctrl, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB(_backend, emulate_tas); \ - TB_DEV_ATTR(_backend, emulate_tas, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB(_backend, emulate_tpu); \ - TB_DEV_ATTR(_backend, emulate_tpu, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB(_backend, emulate_tpws); \ - TB_DEV_ATTR(_backend, emulate_tpws, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB(_backend, emulate_caw); \ - TB_DEV_ATTR(_backend, emulate_caw, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB(_backend, emulate_3pc); \ - TB_DEV_ATTR(_backend, emulate_3pc, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB(_backend, pi_prot_type); \ - TB_DEV_ATTR(_backend, pi_prot_type, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB_RO(_backend, hw_pi_prot_type); \ - TB_DEV_ATTR_RO(_backend, hw_pi_prot_type); \ - DEF_TB_DEV_ATTRIB(_backend, pi_prot_format); \ - TB_DEV_ATTR(_backend, pi_prot_format, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB(_backend, enforce_pr_isids); \ - TB_DEV_ATTR(_backend, enforce_pr_isids, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB(_backend, is_nonrot); \ - TB_DEV_ATTR(_backend, is_nonrot, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB(_backend, emulate_rest_reord); \ - TB_DEV_ATTR(_backend, emulate_rest_reord, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB(_backend, force_pr_aptpl); \ - TB_DEV_ATTR(_backend, force_pr_aptpl, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB_RO(_backend, hw_block_size); \ - TB_DEV_ATTR_RO(_backend, hw_block_size); \ - DEF_TB_DEV_ATTRIB(_backend, block_size); \ - TB_DEV_ATTR(_backend, block_size, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB_RO(_backend, hw_max_sectors); \ - TB_DEV_ATTR_RO(_backend, hw_max_sectors); \ - DEF_TB_DEV_ATTRIB(_backend, optimal_sectors); \ - TB_DEV_ATTR(_backend, optimal_sectors, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB_RO(_backend, hw_queue_depth); \ - TB_DEV_ATTR_RO(_backend, hw_queue_depth); \ - DEF_TB_DEV_ATTRIB(_backend, queue_depth); \ - TB_DEV_ATTR(_backend, queue_depth, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB(_backend, max_unmap_lba_count); \ - TB_DEV_ATTR(_backend, max_unmap_lba_count, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB(_backend, max_unmap_block_desc_count); \ - TB_DEV_ATTR(_backend, max_unmap_block_desc_count, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB(_backend, unmap_granularity); \ - TB_DEV_ATTR(_backend, unmap_granularity, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB(_backend, unmap_granularity_alignment); \ - TB_DEV_ATTR(_backend, unmap_granularity_alignment, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB(_backend, max_write_same_len); \ - TB_DEV_ATTR(_backend, max_write_same_len, S_IRUGO | S_IWUSR); - -#endif /* TARGET_CORE_BACKEND_CONFIGFS_H */ -- cgit v1.2.3-70-g09d2 From 3effdb9094fd06b9c61ecef08d610ae90805fd98 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 10 May 2015 18:14:58 +0200 Subject: target: simplify backend attribute implementation Consolidate the implementation of the backend attributes in a single file and single function per attribute show/store function instead of splitting it into multiple functions in multiple files. Also use the proper strto* helpers for exposed data types, add macros to implement the store methods for the most common data types and share the show methods between the two different attribute implementations. (Fix bogus store_pi_prot_format flag=0 return value - nab) Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_configfs.c | 552 ++++++++++++++++++++++++++++++---- drivers/target/target_core_device.c | 504 ------------------------------- include/target/target_core_backend.h | 29 -- 3 files changed, 486 insertions(+), 599 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index dbf91f02ee5c..4313eea060ed 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -471,82 +471,507 @@ EXPORT_SYMBOL(target_unregister_template); //############################################################################*/ /* Start functions for struct config_item_type tb_dev_attrib_cit */ -#define DEF_TB_DEV_ATTRIB_SHOW(_backend, _name) \ -static ssize_t _backend##_dev_show_attr_##_name( \ - struct se_dev_attrib *da, \ - char *page) \ +#define DEF_TB_DEV_ATTRIB_SHOW(_name) \ +static ssize_t show_##_name(struct se_dev_attrib *da, char *page) \ { \ - return snprintf(page, PAGE_SIZE, "%u\n", \ - (u32)da->da_dev->dev_attrib._name); \ -} - -#define DEF_TB_DEV_ATTRIB_STORE(_backend, _name) \ -static ssize_t _backend##_dev_store_attr_##_name( \ - struct se_dev_attrib *da, \ - const char *page, \ - size_t count) \ + return snprintf(page, PAGE_SIZE, "%u\n", da->_name); \ +} + +DEF_TB_DEV_ATTRIB_SHOW(emulate_model_alias); +DEF_TB_DEV_ATTRIB_SHOW(emulate_dpo); +DEF_TB_DEV_ATTRIB_SHOW(emulate_fua_write); +DEF_TB_DEV_ATTRIB_SHOW(emulate_fua_read); +DEF_TB_DEV_ATTRIB_SHOW(emulate_write_cache); +DEF_TB_DEV_ATTRIB_SHOW(emulate_ua_intlck_ctrl); +DEF_TB_DEV_ATTRIB_SHOW(emulate_tas); +DEF_TB_DEV_ATTRIB_SHOW(emulate_tpu); +DEF_TB_DEV_ATTRIB_SHOW(emulate_tpws); +DEF_TB_DEV_ATTRIB_SHOW(emulate_caw); +DEF_TB_DEV_ATTRIB_SHOW(emulate_3pc); +DEF_TB_DEV_ATTRIB_SHOW(pi_prot_type); +DEF_TB_DEV_ATTRIB_SHOW(hw_pi_prot_type); +DEF_TB_DEV_ATTRIB_SHOW(pi_prot_format); +DEF_TB_DEV_ATTRIB_SHOW(enforce_pr_isids); +DEF_TB_DEV_ATTRIB_SHOW(is_nonrot); +DEF_TB_DEV_ATTRIB_SHOW(emulate_rest_reord); +DEF_TB_DEV_ATTRIB_SHOW(force_pr_aptpl); +DEF_TB_DEV_ATTRIB_SHOW(hw_block_size); +DEF_TB_DEV_ATTRIB_SHOW(block_size); +DEF_TB_DEV_ATTRIB_SHOW(hw_max_sectors); +DEF_TB_DEV_ATTRIB_SHOW(optimal_sectors); +DEF_TB_DEV_ATTRIB_SHOW(hw_queue_depth); +DEF_TB_DEV_ATTRIB_SHOW(queue_depth); +DEF_TB_DEV_ATTRIB_SHOW(max_unmap_lba_count); +DEF_TB_DEV_ATTRIB_SHOW(max_unmap_block_desc_count); +DEF_TB_DEV_ATTRIB_SHOW(unmap_granularity); +DEF_TB_DEV_ATTRIB_SHOW(unmap_granularity_alignment); +DEF_TB_DEV_ATTRIB_SHOW(max_write_same_len); + +#define DEF_TB_DEV_ATTRIB_STORE_U32(_name) \ +static ssize_t store_##_name(struct se_dev_attrib *da, const char *page,\ + size_t count) \ { \ - unsigned long val; \ + u32 val; \ int ret; \ \ - ret = kstrtoul(page, 0, &val); \ - if (ret < 0) { \ - pr_err("kstrtoul() failed with ret: %d\n", ret); \ - return -EINVAL; \ - } \ - ret = se_dev_set_##_name(da->da_dev, (u32)val); \ + ret = kstrtou32(page, 0, &val); \ + if (ret < 0) \ + return ret; \ + da->_name = val; \ + return count; \ +} + +DEF_TB_DEV_ATTRIB_STORE_U32(max_unmap_lba_count); +DEF_TB_DEV_ATTRIB_STORE_U32(max_unmap_block_desc_count); +DEF_TB_DEV_ATTRIB_STORE_U32(unmap_granularity); +DEF_TB_DEV_ATTRIB_STORE_U32(unmap_granularity_alignment); +DEF_TB_DEV_ATTRIB_STORE_U32(max_write_same_len); + +#define DEF_TB_DEV_ATTRIB_STORE_BOOL(_name) \ +static ssize_t store_##_name(struct se_dev_attrib *da, const char *page,\ + size_t count) \ +{ \ + bool flag; \ + int ret; \ \ - return (!ret) ? count : -EINVAL; \ + ret = strtobool(page, &flag); \ + if (ret < 0) \ + return ret; \ + da->_name = flag; \ + return count; \ +} + +DEF_TB_DEV_ATTRIB_STORE_BOOL(emulate_fua_write); +DEF_TB_DEV_ATTRIB_STORE_BOOL(emulate_caw); +DEF_TB_DEV_ATTRIB_STORE_BOOL(emulate_3pc); +DEF_TB_DEV_ATTRIB_STORE_BOOL(enforce_pr_isids); +DEF_TB_DEV_ATTRIB_STORE_BOOL(is_nonrot); + +#define DEF_TB_DEV_ATTRIB_STORE_STUB(_name) \ +static ssize_t store_##_name(struct se_dev_attrib *da, const char *page,\ + size_t count) \ +{ \ + printk_once(KERN_WARNING \ + "ignoring deprecated ##_name## attribute\n"); \ + return count; \ +} + +DEF_TB_DEV_ATTRIB_STORE_STUB(emulate_dpo); +DEF_TB_DEV_ATTRIB_STORE_STUB(emulate_fua_read); + +static void dev_set_t10_wwn_model_alias(struct se_device *dev) +{ + const char *configname; + + configname = config_item_name(&dev->dev_group.cg_item); + if (strlen(configname) >= 16) { + pr_warn("dev[%p]: Backstore name '%s' is too long for " + "INQUIRY_MODEL, truncating to 16 bytes\n", dev, + configname); + } + snprintf(&dev->t10_wwn.model[0], 16, "%s", configname); +} + +static ssize_t store_emulate_model_alias(struct se_dev_attrib *da, + const char *page, size_t count) +{ + struct se_device *dev = da->da_dev; + bool flag; + int ret; + + if (dev->export_count) { + pr_err("dev[%p]: Unable to change model alias" + " while export_count is %d\n", + dev, dev->export_count); + return -EINVAL; + } + + ret = strtobool(page, &flag); + if (ret < 0) + return ret; + + if (flag) { + dev_set_t10_wwn_model_alias(dev); + } else { + strncpy(&dev->t10_wwn.model[0], + dev->transport->inquiry_prod, 16); + } + da->emulate_model_alias = flag; + return count; +} + +static ssize_t store_emulate_write_cache(struct se_dev_attrib *da, + const char *page, size_t count) +{ + bool flag; + int ret; + + ret = strtobool(page, &flag); + if (ret < 0) + return ret; + + if (flag && da->da_dev->transport->get_write_cache) { + pr_err("emulate_write_cache not supported for this device\n"); + return -EINVAL; + } + + da->emulate_write_cache = flag; + pr_debug("dev[%p]: SE Device WRITE_CACHE_EMULATION flag: %d\n", + da->da_dev, flag); + return count; +} + +static ssize_t store_emulate_ua_intlck_ctrl(struct se_dev_attrib *da, + const char *page, size_t count) +{ + u32 val; + int ret; + + ret = kstrtou32(page, 0, &val); + if (ret < 0) + return ret; + + if (val != 0 && val != 1 && val != 2) { + pr_err("Illegal value %d\n", val); + return -EINVAL; + } + + if (da->da_dev->export_count) { + pr_err("dev[%p]: Unable to change SE Device" + " UA_INTRLCK_CTRL while export_count is %d\n", + da->da_dev, da->da_dev->export_count); + return -EINVAL; + } + da->emulate_ua_intlck_ctrl = val; + pr_debug("dev[%p]: SE Device UA_INTRLCK_CTRL flag: %d\n", + da->da_dev, val); + return count; +} + +static ssize_t store_emulate_tas(struct se_dev_attrib *da, + const char *page, size_t count) +{ + bool flag; + int ret; + + ret = strtobool(page, &flag); + if (ret < 0) + return ret; + + if (da->da_dev->export_count) { + pr_err("dev[%p]: Unable to change SE Device TAS while" + " export_count is %d\n", + da->da_dev, da->da_dev->export_count); + return -EINVAL; + } + da->emulate_tas = flag; + pr_debug("dev[%p]: SE Device TASK_ABORTED status bit: %s\n", + da->da_dev, flag ? "Enabled" : "Disabled"); + + return count; +} + +static ssize_t store_emulate_tpu(struct se_dev_attrib *da, + const char *page, size_t count) +{ + bool flag; + int ret; + + ret = strtobool(page, &flag); + if (ret < 0) + return ret; + + /* + * We expect this value to be non-zero when generic Block Layer + * Discard supported is detected iblock_create_virtdevice(). + */ + if (flag && !da->max_unmap_block_desc_count) { + pr_err("Generic Block Discard not supported\n"); + return -ENOSYS; + } + + da->emulate_tpu = flag; + pr_debug("dev[%p]: SE Device Thin Provisioning UNMAP bit: %d\n", + da->da_dev, flag); + return count; +} + +static ssize_t store_emulate_tpws(struct se_dev_attrib *da, + const char *page, size_t count) +{ + bool flag; + int ret; + + ret = strtobool(page, &flag); + if (ret < 0) + return ret; + + /* + * We expect this value to be non-zero when generic Block Layer + * Discard supported is detected iblock_create_virtdevice(). + */ + if (flag && !da->max_unmap_block_desc_count) { + pr_err("Generic Block Discard not supported\n"); + return -ENOSYS; + } + + da->emulate_tpws = flag; + pr_debug("dev[%p]: SE Device Thin Provisioning WRITE_SAME: %d\n", + da->da_dev, flag); + return count; +} + +static ssize_t store_pi_prot_type(struct se_dev_attrib *da, + const char *page, size_t count) +{ + int old_prot = da->pi_prot_type, ret; + struct se_device *dev = da->da_dev; + u32 flag; + + ret = kstrtou32(page, 0, &flag); + if (ret < 0) + return ret; + + if (flag != 0 && flag != 1 && flag != 2 && flag != 3) { + pr_err("Illegal value %d for pi_prot_type\n", flag); + return -EINVAL; + } + if (flag == 2) { + pr_err("DIF TYPE2 protection currently not supported\n"); + return -ENOSYS; + } + if (da->hw_pi_prot_type) { + pr_warn("DIF protection enabled on underlying hardware," + " ignoring\n"); + return count; + } + if (!dev->transport->init_prot || !dev->transport->free_prot) { + /* 0 is only allowed value for non-supporting backends */ + if (flag == 0) + return 0; + + pr_err("DIF protection not supported by backend: %s\n", + dev->transport->name); + return -ENOSYS; + } + if (!(dev->dev_flags & DF_CONFIGURED)) { + pr_err("DIF protection requires device to be configured\n"); + return -ENODEV; + } + if (dev->export_count) { + pr_err("dev[%p]: Unable to change SE Device PROT type while" + " export_count is %d\n", dev, dev->export_count); + return -EINVAL; + } + + da->pi_prot_type = flag; + + if (flag && !old_prot) { + ret = dev->transport->init_prot(dev); + if (ret) { + da->pi_prot_type = old_prot; + return ret; + } + + } else if (!flag && old_prot) { + dev->transport->free_prot(dev); + } + + pr_debug("dev[%p]: SE Device Protection Type: %d\n", dev, flag); + return count; +} + +static ssize_t store_pi_prot_format(struct se_dev_attrib *da, + const char *page, size_t count) +{ + struct se_device *dev = da->da_dev; + bool flag; + int ret; + + ret = strtobool(page, &flag); + if (ret < 0) + return ret; + + if (!flag) + return count; + + if (!dev->transport->format_prot) { + pr_err("DIF protection format not supported by backend %s\n", + dev->transport->name); + return -ENOSYS; + } + if (!(dev->dev_flags & DF_CONFIGURED)) { + pr_err("DIF protection format requires device to be configured\n"); + return -ENODEV; + } + if (dev->export_count) { + pr_err("dev[%p]: Unable to format SE Device PROT type while" + " export_count is %d\n", dev, dev->export_count); + return -EINVAL; + } + + ret = dev->transport->format_prot(dev); + if (ret) + return ret; + + pr_debug("dev[%p]: SE Device Protection Format complete\n", dev); + return count; +} + +static ssize_t store_force_pr_aptpl(struct se_dev_attrib *da, + const char *page, size_t count) +{ + bool flag; + int ret; + + ret = strtobool(page, &flag); + if (ret < 0) + return ret; + if (da->da_dev->export_count) { + pr_err("dev[%p]: Unable to set force_pr_aptpl while" + " export_count is %d\n", + da->da_dev, da->da_dev->export_count); + return -EINVAL; + } + + da->force_pr_aptpl = flag; + pr_debug("dev[%p]: SE Device force_pr_aptpl: %d\n", da->da_dev, flag); + return count; +} + +static ssize_t store_emulate_rest_reord(struct se_dev_attrib *da, + const char *page, size_t count) +{ + bool flag; + int ret; + + ret = strtobool(page, &flag); + if (ret < 0) + return ret; + + if (flag != 0) { + printk(KERN_ERR "dev[%p]: SE Device emulation of restricted" + " reordering not implemented\n", da->da_dev); + return -ENOSYS; + } + da->emulate_rest_reord = flag; + pr_debug("dev[%p]: SE Device emulate_rest_reord: %d\n", + da->da_dev, flag); + return count; } -#define DEF_TB_DEV_ATTRIB(_backend, _name) \ -DEF_TB_DEV_ATTRIB_SHOW(_backend, _name); \ -DEF_TB_DEV_ATTRIB_STORE(_backend, _name); +/* + * Note, this can only be called on unexported SE Device Object. + */ +static ssize_t store_queue_depth(struct se_dev_attrib *da, + const char *page, size_t count) +{ + struct se_device *dev = da->da_dev; + u32 val; + int ret; -#define DEF_TB_DEV_ATTRIB_RO(_backend, name) \ -DEF_TB_DEV_ATTRIB_SHOW(_backend, name); + ret = kstrtou32(page, 0, &val); + if (ret < 0) + return ret; + + if (dev->export_count) { + pr_err("dev[%p]: Unable to change SE Device TCQ while" + " export_count is %d\n", + dev, dev->export_count); + return -EINVAL; + } + if (!val) { + pr_err("dev[%p]: Illegal ZERO value for queue_depth\n", dev); + return -EINVAL; + } + + if (val > dev->dev_attrib.queue_depth) { + if (val > dev->dev_attrib.hw_queue_depth) { + pr_err("dev[%p]: Passed queue_depth:" + " %u exceeds TCM/SE_Device MAX" + " TCQ: %u\n", dev, val, + dev->dev_attrib.hw_queue_depth); + return -EINVAL; + } + } + da->queue_depth = dev->queue_depth = val; + pr_debug("dev[%p]: SE Device TCQ Depth changed to: %u\n", dev, val); + return count; +} + +static ssize_t store_optimal_sectors(struct se_dev_attrib *da, + const char *page, size_t count) +{ + u32 val; + int ret; + + ret = kstrtou32(page, 0, &val); + if (ret < 0) + return ret; + + if (da->da_dev->export_count) { + pr_err("dev[%p]: Unable to change SE Device" + " optimal_sectors while export_count is %d\n", + da->da_dev, da->da_dev->export_count); + return -EINVAL; + } + if (val > da->hw_max_sectors) { + pr_err("dev[%p]: Passed optimal_sectors %u cannot be" + " greater than hw_max_sectors: %u\n", + da->da_dev, val, da->hw_max_sectors); + return -EINVAL; + } + + da->optimal_sectors = val; + pr_debug("dev[%p]: SE Device optimal_sectors changed to %u\n", + da->da_dev, val); + return count; +} + +static ssize_t store_block_size(struct se_dev_attrib *da, + const char *page, size_t count) +{ + u32 val; + int ret; + + ret = kstrtou32(page, 0, &val); + if (ret < 0) + return ret; + + if (da->da_dev->export_count) { + pr_err("dev[%p]: Unable to change SE Device block_size" + " while export_count is %d\n", + da->da_dev, da->da_dev->export_count); + return -EINVAL; + } + + if (val != 512 && val != 1024 && val != 2048 && val != 4096) { + pr_err("dev[%p]: Illegal value for block_device: %u" + " for SE device, must be 512, 1024, 2048 or 4096\n", + da->da_dev, val); + return -EINVAL; + } + + da->block_size = val; + if (da->max_bytes_per_io) + da->hw_max_sectors = da->max_bytes_per_io / val; + + pr_debug("dev[%p]: SE Device block_size changed to %u\n", + da->da_dev, val); + return count; +} CONFIGFS_EATTR_STRUCT(target_backend_dev_attrib, se_dev_attrib); #define TB_DEV_ATTR(_backend, _name, _mode) \ static struct target_backend_dev_attrib_attribute _backend##_dev_attrib_##_name = \ - __CONFIGFS_EATTR(_name, _mode, \ - _backend##_dev_show_attr_##_name, \ - _backend##_dev_store_attr_##_name); + __CONFIGFS_EATTR(_name, _mode, \ + show_##_name, \ + store_##_name); -#define TB_DEV_ATTR_RO(_backend, _name) \ +#define TB_DEV_ATTR_RO(_backend, _name) \ static struct target_backend_dev_attrib_attribute _backend##_dev_attrib_##_name = \ __CONFIGFS_EATTR_RO(_name, \ - _backend##_dev_show_attr_##_name); - -DEF_TB_DEV_ATTRIB(target_core, emulate_model_alias); -DEF_TB_DEV_ATTRIB(target_core, emulate_dpo); -DEF_TB_DEV_ATTRIB(target_core, emulate_fua_write); -DEF_TB_DEV_ATTRIB(target_core, emulate_fua_read); -DEF_TB_DEV_ATTRIB(target_core, emulate_write_cache); -DEF_TB_DEV_ATTRIB(target_core, emulate_ua_intlck_ctrl); -DEF_TB_DEV_ATTRIB(target_core, emulate_tas); -DEF_TB_DEV_ATTRIB(target_core, emulate_tpu); -DEF_TB_DEV_ATTRIB(target_core, emulate_tpws); -DEF_TB_DEV_ATTRIB(target_core, emulate_caw); -DEF_TB_DEV_ATTRIB(target_core, emulate_3pc); -DEF_TB_DEV_ATTRIB(target_core, pi_prot_type); -DEF_TB_DEV_ATTRIB_RO(target_core, hw_pi_prot_type); -DEF_TB_DEV_ATTRIB(target_core, pi_prot_format); -DEF_TB_DEV_ATTRIB(target_core, enforce_pr_isids); -DEF_TB_DEV_ATTRIB(target_core, is_nonrot); -DEF_TB_DEV_ATTRIB(target_core, emulate_rest_reord); -DEF_TB_DEV_ATTRIB(target_core, force_pr_aptpl); -DEF_TB_DEV_ATTRIB_RO(target_core, hw_block_size); -DEF_TB_DEV_ATTRIB(target_core, block_size); -DEF_TB_DEV_ATTRIB_RO(target_core, hw_max_sectors); -DEF_TB_DEV_ATTRIB(target_core, optimal_sectors); -DEF_TB_DEV_ATTRIB_RO(target_core, hw_queue_depth); -DEF_TB_DEV_ATTRIB(target_core, queue_depth); -DEF_TB_DEV_ATTRIB(target_core, max_unmap_lba_count); -DEF_TB_DEV_ATTRIB(target_core, max_unmap_block_desc_count); -DEF_TB_DEV_ATTRIB(target_core, unmap_granularity); -DEF_TB_DEV_ATTRIB(target_core, unmap_granularity_alignment); -DEF_TB_DEV_ATTRIB(target_core, max_write_same_len); + show_##_name); TB_DEV_ATTR(target_core, emulate_model_alias, S_IRUGO | S_IWUSR); TB_DEV_ATTR(target_core, emulate_dpo, S_IRUGO | S_IWUSR); @@ -620,11 +1045,6 @@ struct configfs_attribute *sbc_attrib_attrs[] = { }; EXPORT_SYMBOL(sbc_attrib_attrs); -DEF_TB_DEV_ATTRIB_RO(target_pt, hw_pi_prot_type); -DEF_TB_DEV_ATTRIB_RO(target_pt, hw_block_size); -DEF_TB_DEV_ATTRIB_RO(target_pt, hw_max_sectors); -DEF_TB_DEV_ATTRIB_RO(target_pt, hw_queue_depth); - TB_DEV_ATTR_RO(target_pt, hw_pi_prot_type); TB_DEV_ATTR_RO(target_pt, hw_block_size); TB_DEV_ATTR_RO(target_pt, hw_max_sectors); diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index af906f1caaa7..22f1e180d8ee 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -665,510 +665,6 @@ bool se_dev_check_wce(struct se_device *dev) return wce; } -int se_dev_set_max_unmap_lba_count( - struct se_device *dev, - u32 max_unmap_lba_count) -{ - dev->dev_attrib.max_unmap_lba_count = max_unmap_lba_count; - pr_debug("dev[%p]: Set max_unmap_lba_count: %u\n", - dev, dev->dev_attrib.max_unmap_lba_count); - return 0; -} -EXPORT_SYMBOL(se_dev_set_max_unmap_lba_count); - -int se_dev_set_max_unmap_block_desc_count( - struct se_device *dev, - u32 max_unmap_block_desc_count) -{ - dev->dev_attrib.max_unmap_block_desc_count = - max_unmap_block_desc_count; - pr_debug("dev[%p]: Set max_unmap_block_desc_count: %u\n", - dev, dev->dev_attrib.max_unmap_block_desc_count); - return 0; -} -EXPORT_SYMBOL(se_dev_set_max_unmap_block_desc_count); - -int se_dev_set_unmap_granularity( - struct se_device *dev, - u32 unmap_granularity) -{ - dev->dev_attrib.unmap_granularity = unmap_granularity; - pr_debug("dev[%p]: Set unmap_granularity: %u\n", - dev, dev->dev_attrib.unmap_granularity); - return 0; -} -EXPORT_SYMBOL(se_dev_set_unmap_granularity); - -int se_dev_set_unmap_granularity_alignment( - struct se_device *dev, - u32 unmap_granularity_alignment) -{ - dev->dev_attrib.unmap_granularity_alignment = unmap_granularity_alignment; - pr_debug("dev[%p]: Set unmap_granularity_alignment: %u\n", - dev, dev->dev_attrib.unmap_granularity_alignment); - return 0; -} -EXPORT_SYMBOL(se_dev_set_unmap_granularity_alignment); - -int se_dev_set_max_write_same_len( - struct se_device *dev, - u32 max_write_same_len) -{ - dev->dev_attrib.max_write_same_len = max_write_same_len; - pr_debug("dev[%p]: Set max_write_same_len: %u\n", - dev, dev->dev_attrib.max_write_same_len); - return 0; -} -EXPORT_SYMBOL(se_dev_set_max_write_same_len); - -static void dev_set_t10_wwn_model_alias(struct se_device *dev) -{ - const char *configname; - - configname = config_item_name(&dev->dev_group.cg_item); - if (strlen(configname) >= 16) { - pr_warn("dev[%p]: Backstore name '%s' is too long for " - "INQUIRY_MODEL, truncating to 16 bytes\n", dev, - configname); - } - snprintf(&dev->t10_wwn.model[0], 16, "%s", configname); -} - -int se_dev_set_emulate_model_alias(struct se_device *dev, int flag) -{ - if (dev->export_count) { - pr_err("dev[%p]: Unable to change model alias" - " while export_count is %d\n", - dev, dev->export_count); - return -EINVAL; - } - - if (flag != 0 && flag != 1) { - pr_err("Illegal value %d\n", flag); - return -EINVAL; - } - - if (flag) { - dev_set_t10_wwn_model_alias(dev); - } else { - strncpy(&dev->t10_wwn.model[0], - dev->transport->inquiry_prod, 16); - } - dev->dev_attrib.emulate_model_alias = flag; - - return 0; -} -EXPORT_SYMBOL(se_dev_set_emulate_model_alias); - -int se_dev_set_emulate_dpo(struct se_device *dev, int flag) -{ - printk_once(KERN_WARNING - "ignoring deprecated emulate_dpo attribute\n"); - return 0; -} -EXPORT_SYMBOL(se_dev_set_emulate_dpo); - -int se_dev_set_emulate_fua_write(struct se_device *dev, int flag) -{ - if (flag != 0 && flag != 1) { - pr_err("Illegal value %d\n", flag); - return -EINVAL; - } - if (flag && - dev->transport->get_write_cache) { - pr_warn("emulate_fua_write not supported for this device, ignoring\n"); - return 0; - } - if (dev->export_count) { - pr_err("emulate_fua_write cannot be changed with active" - " exports: %d\n", dev->export_count); - return -EINVAL; - } - dev->dev_attrib.emulate_fua_write = flag; - pr_debug("dev[%p]: SE Device Forced Unit Access WRITEs: %d\n", - dev, dev->dev_attrib.emulate_fua_write); - return 0; -} -EXPORT_SYMBOL(se_dev_set_emulate_fua_write); - -int se_dev_set_emulate_fua_read(struct se_device *dev, int flag) -{ - printk_once(KERN_WARNING - "ignoring deprecated emulate_fua_read attribute\n"); - return 0; -} -EXPORT_SYMBOL(se_dev_set_emulate_fua_read); - -int se_dev_set_emulate_write_cache(struct se_device *dev, int flag) -{ - if (flag != 0 && flag != 1) { - pr_err("Illegal value %d\n", flag); - return -EINVAL; - } - if (flag && - dev->transport->get_write_cache) { - pr_err("emulate_write_cache not supported for this device\n"); - return -EINVAL; - } - if (dev->export_count) { - pr_err("emulate_write_cache cannot be changed with active" - " exports: %d\n", dev->export_count); - return -EINVAL; - } - dev->dev_attrib.emulate_write_cache = flag; - pr_debug("dev[%p]: SE Device WRITE_CACHE_EMULATION flag: %d\n", - dev, dev->dev_attrib.emulate_write_cache); - return 0; -} -EXPORT_SYMBOL(se_dev_set_emulate_write_cache); - -int se_dev_set_emulate_ua_intlck_ctrl(struct se_device *dev, int flag) -{ - if ((flag != 0) && (flag != 1) && (flag != 2)) { - pr_err("Illegal value %d\n", flag); - return -EINVAL; - } - - if (dev->export_count) { - pr_err("dev[%p]: Unable to change SE Device" - " UA_INTRLCK_CTRL while export_count is %d\n", - dev, dev->export_count); - return -EINVAL; - } - dev->dev_attrib.emulate_ua_intlck_ctrl = flag; - pr_debug("dev[%p]: SE Device UA_INTRLCK_CTRL flag: %d\n", - dev, dev->dev_attrib.emulate_ua_intlck_ctrl); - - return 0; -} -EXPORT_SYMBOL(se_dev_set_emulate_ua_intlck_ctrl); - -int se_dev_set_emulate_tas(struct se_device *dev, int flag) -{ - if ((flag != 0) && (flag != 1)) { - pr_err("Illegal value %d\n", flag); - return -EINVAL; - } - - if (dev->export_count) { - pr_err("dev[%p]: Unable to change SE Device TAS while" - " export_count is %d\n", - dev, dev->export_count); - return -EINVAL; - } - dev->dev_attrib.emulate_tas = flag; - pr_debug("dev[%p]: SE Device TASK_ABORTED status bit: %s\n", - dev, (dev->dev_attrib.emulate_tas) ? "Enabled" : "Disabled"); - - return 0; -} -EXPORT_SYMBOL(se_dev_set_emulate_tas); - -int se_dev_set_emulate_tpu(struct se_device *dev, int flag) -{ - if ((flag != 0) && (flag != 1)) { - pr_err("Illegal value %d\n", flag); - return -EINVAL; - } - /* - * We expect this value to be non-zero when generic Block Layer - * Discard supported is detected iblock_create_virtdevice(). - */ - if (flag && !dev->dev_attrib.max_unmap_block_desc_count) { - pr_err("Generic Block Discard not supported\n"); - return -ENOSYS; - } - - dev->dev_attrib.emulate_tpu = flag; - pr_debug("dev[%p]: SE Device Thin Provisioning UNMAP bit: %d\n", - dev, flag); - return 0; -} -EXPORT_SYMBOL(se_dev_set_emulate_tpu); - -int se_dev_set_emulate_tpws(struct se_device *dev, int flag) -{ - if ((flag != 0) && (flag != 1)) { - pr_err("Illegal value %d\n", flag); - return -EINVAL; - } - /* - * We expect this value to be non-zero when generic Block Layer - * Discard supported is detected iblock_create_virtdevice(). - */ - if (flag && !dev->dev_attrib.max_unmap_block_desc_count) { - pr_err("Generic Block Discard not supported\n"); - return -ENOSYS; - } - - dev->dev_attrib.emulate_tpws = flag; - pr_debug("dev[%p]: SE Device Thin Provisioning WRITE_SAME: %d\n", - dev, flag); - return 0; -} -EXPORT_SYMBOL(se_dev_set_emulate_tpws); - -int se_dev_set_emulate_caw(struct se_device *dev, int flag) -{ - if (flag != 0 && flag != 1) { - pr_err("Illegal value %d\n", flag); - return -EINVAL; - } - dev->dev_attrib.emulate_caw = flag; - pr_debug("dev[%p]: SE Device CompareAndWrite (AtomicTestandSet): %d\n", - dev, flag); - - return 0; -} -EXPORT_SYMBOL(se_dev_set_emulate_caw); - -int se_dev_set_emulate_3pc(struct se_device *dev, int flag) -{ - if (flag != 0 && flag != 1) { - pr_err("Illegal value %d\n", flag); - return -EINVAL; - } - dev->dev_attrib.emulate_3pc = flag; - pr_debug("dev[%p]: SE Device 3rd Party Copy (EXTENDED_COPY): %d\n", - dev, flag); - - return 0; -} -EXPORT_SYMBOL(se_dev_set_emulate_3pc); - -int se_dev_set_pi_prot_type(struct se_device *dev, int flag) -{ - int rc, old_prot = dev->dev_attrib.pi_prot_type; - - if (flag != 0 && flag != 1 && flag != 2 && flag != 3) { - pr_err("Illegal value %d for pi_prot_type\n", flag); - return -EINVAL; - } - if (flag == 2) { - pr_err("DIF TYPE2 protection currently not supported\n"); - return -ENOSYS; - } - if (dev->dev_attrib.hw_pi_prot_type) { - pr_warn("DIF protection enabled on underlying hardware," - " ignoring\n"); - return 0; - } - if (!dev->transport->init_prot || !dev->transport->free_prot) { - /* 0 is only allowed value for non-supporting backends */ - if (flag == 0) - return 0; - - pr_err("DIF protection not supported by backend: %s\n", - dev->transport->name); - return -ENOSYS; - } - if (!(dev->dev_flags & DF_CONFIGURED)) { - pr_err("DIF protection requires device to be configured\n"); - return -ENODEV; - } - if (dev->export_count) { - pr_err("dev[%p]: Unable to change SE Device PROT type while" - " export_count is %d\n", dev, dev->export_count); - return -EINVAL; - } - - dev->dev_attrib.pi_prot_type = flag; - - if (flag && !old_prot) { - rc = dev->transport->init_prot(dev); - if (rc) { - dev->dev_attrib.pi_prot_type = old_prot; - return rc; - } - - } else if (!flag && old_prot) { - dev->transport->free_prot(dev); - } - pr_debug("dev[%p]: SE Device Protection Type: %d\n", dev, flag); - - return 0; -} -EXPORT_SYMBOL(se_dev_set_pi_prot_type); - -int se_dev_set_pi_prot_format(struct se_device *dev, int flag) -{ - int rc; - - if (!flag) - return 0; - - if (flag != 1) { - pr_err("Illegal value %d for pi_prot_format\n", flag); - return -EINVAL; - } - if (!dev->transport->format_prot) { - pr_err("DIF protection format not supported by backend %s\n", - dev->transport->name); - return -ENOSYS; - } - if (!(dev->dev_flags & DF_CONFIGURED)) { - pr_err("DIF protection format requires device to be configured\n"); - return -ENODEV; - } - if (dev->export_count) { - pr_err("dev[%p]: Unable to format SE Device PROT type while" - " export_count is %d\n", dev, dev->export_count); - return -EINVAL; - } - - rc = dev->transport->format_prot(dev); - if (rc) - return rc; - - pr_debug("dev[%p]: SE Device Protection Format complete\n", dev); - - return 0; -} -EXPORT_SYMBOL(se_dev_set_pi_prot_format); - -int se_dev_set_enforce_pr_isids(struct se_device *dev, int flag) -{ - if ((flag != 0) && (flag != 1)) { - pr_err("Illegal value %d\n", flag); - return -EINVAL; - } - dev->dev_attrib.enforce_pr_isids = flag; - pr_debug("dev[%p]: SE Device enforce_pr_isids bit: %s\n", dev, - (dev->dev_attrib.enforce_pr_isids) ? "Enabled" : "Disabled"); - return 0; -} -EXPORT_SYMBOL(se_dev_set_enforce_pr_isids); - -int se_dev_set_force_pr_aptpl(struct se_device *dev, int flag) -{ - if ((flag != 0) && (flag != 1)) { - printk(KERN_ERR "Illegal value %d\n", flag); - return -EINVAL; - } - if (dev->export_count) { - pr_err("dev[%p]: Unable to set force_pr_aptpl while" - " export_count is %d\n", dev, dev->export_count); - return -EINVAL; - } - - dev->dev_attrib.force_pr_aptpl = flag; - pr_debug("dev[%p]: SE Device force_pr_aptpl: %d\n", dev, flag); - return 0; -} -EXPORT_SYMBOL(se_dev_set_force_pr_aptpl); - -int se_dev_set_is_nonrot(struct se_device *dev, int flag) -{ - if ((flag != 0) && (flag != 1)) { - printk(KERN_ERR "Illegal value %d\n", flag); - return -EINVAL; - } - dev->dev_attrib.is_nonrot = flag; - pr_debug("dev[%p]: SE Device is_nonrot bit: %d\n", - dev, flag); - return 0; -} -EXPORT_SYMBOL(se_dev_set_is_nonrot); - -int se_dev_set_emulate_rest_reord(struct se_device *dev, int flag) -{ - if (flag != 0) { - printk(KERN_ERR "dev[%p]: SE Device emulation of restricted" - " reordering not implemented\n", dev); - return -ENOSYS; - } - dev->dev_attrib.emulate_rest_reord = flag; - pr_debug("dev[%p]: SE Device emulate_rest_reord: %d\n", dev, flag); - return 0; -} -EXPORT_SYMBOL(se_dev_set_emulate_rest_reord); - -/* - * Note, this can only be called on unexported SE Device Object. - */ -int se_dev_set_queue_depth(struct se_device *dev, u32 queue_depth) -{ - if (dev->export_count) { - pr_err("dev[%p]: Unable to change SE Device TCQ while" - " export_count is %d\n", - dev, dev->export_count); - return -EINVAL; - } - if (!queue_depth) { - pr_err("dev[%p]: Illegal ZERO value for queue" - "_depth\n", dev); - return -EINVAL; - } - - if (queue_depth > dev->dev_attrib.queue_depth) { - if (queue_depth > dev->dev_attrib.hw_queue_depth) { - pr_err("dev[%p]: Passed queue_depth:" - " %u exceeds TCM/SE_Device MAX" - " TCQ: %u\n", dev, queue_depth, - dev->dev_attrib.hw_queue_depth); - return -EINVAL; - } - } - dev->dev_attrib.queue_depth = dev->queue_depth = queue_depth; - pr_debug("dev[%p]: SE Device TCQ Depth changed to: %u\n", - dev, queue_depth); - return 0; -} -EXPORT_SYMBOL(se_dev_set_queue_depth); - -int se_dev_set_optimal_sectors(struct se_device *dev, u32 optimal_sectors) -{ - if (dev->export_count) { - pr_err("dev[%p]: Unable to change SE Device" - " optimal_sectors while export_count is %d\n", - dev, dev->export_count); - return -EINVAL; - } - if (optimal_sectors > dev->dev_attrib.hw_max_sectors) { - pr_err("dev[%p]: Passed optimal_sectors %u cannot be" - " greater than hw_max_sectors: %u\n", dev, - optimal_sectors, dev->dev_attrib.hw_max_sectors); - return -EINVAL; - } - - dev->dev_attrib.optimal_sectors = optimal_sectors; - pr_debug("dev[%p]: SE Device optimal_sectors changed to %u\n", - dev, optimal_sectors); - return 0; -} -EXPORT_SYMBOL(se_dev_set_optimal_sectors); - -int se_dev_set_block_size(struct se_device *dev, u32 block_size) -{ - if (dev->export_count) { - pr_err("dev[%p]: Unable to change SE Device block_size" - " while export_count is %d\n", - dev, dev->export_count); - return -EINVAL; - } - - if ((block_size != 512) && - (block_size != 1024) && - (block_size != 2048) && - (block_size != 4096)) { - pr_err("dev[%p]: Illegal value for block_device: %u" - " for SE device, must be 512, 1024, 2048 or 4096\n", - dev, block_size); - return -EINVAL; - } - - dev->dev_attrib.block_size = block_size; - pr_debug("dev[%p]: SE Device block_size changed to %u\n", - dev, block_size); - - if (dev->dev_attrib.max_bytes_per_io) - dev->dev_attrib.hw_max_sectors = - dev->dev_attrib.max_bytes_per_io / block_size; - - return 0; -} -EXPORT_SYMBOL(se_dev_set_block_size); - int core_dev_add_lun( struct se_portal_group *tpg, struct se_device *dev, diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index 2d5610516494..566c7d27f6d0 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -94,35 +94,6 @@ sense_reason_t transport_generic_map_mem_to_cmd(struct se_cmd *, struct scatterlist *, u32, struct scatterlist *, u32); bool target_lun_is_rdonly(struct se_cmd *); - -/* attribute helpers from target_core_device.c for backend drivers */ -bool se_dev_check_wce(struct se_device *); -int se_dev_set_max_unmap_lba_count(struct se_device *, u32); -int se_dev_set_max_unmap_block_desc_count(struct se_device *, u32); -int se_dev_set_unmap_granularity(struct se_device *, u32); -int se_dev_set_unmap_granularity_alignment(struct se_device *, u32); -int se_dev_set_max_write_same_len(struct se_device *, u32); -int se_dev_set_emulate_model_alias(struct se_device *, int); -int se_dev_set_emulate_dpo(struct se_device *, int); -int se_dev_set_emulate_fua_write(struct se_device *, int); -int se_dev_set_emulate_fua_read(struct se_device *, int); -int se_dev_set_emulate_write_cache(struct se_device *, int); -int se_dev_set_emulate_ua_intlck_ctrl(struct se_device *, int); -int se_dev_set_emulate_tas(struct se_device *, int); -int se_dev_set_emulate_tpu(struct se_device *, int); -int se_dev_set_emulate_tpws(struct se_device *, int); -int se_dev_set_emulate_caw(struct se_device *, int); -int se_dev_set_emulate_3pc(struct se_device *, int); -int se_dev_set_pi_prot_type(struct se_device *, int); -int se_dev_set_pi_prot_format(struct se_device *, int); -int se_dev_set_enforce_pr_isids(struct se_device *, int); -int se_dev_set_force_pr_aptpl(struct se_device *, int); -int se_dev_set_is_nonrot(struct se_device *, int); -int se_dev_set_emulate_rest_reord(struct se_device *dev, int); -int se_dev_set_queue_depth(struct se_device *, u32); -int se_dev_set_max_sectors(struct se_device *, u32); -int se_dev_set_optimal_sectors(struct se_device *, u32); -int se_dev_set_block_size(struct se_device *, u32); sense_reason_t passthrough_parse_cdb(struct se_cmd *cmd, sense_reason_t (*exec_cmd)(struct se_cmd *cmd)); -- cgit v1.2.3-70-g09d2 From b3eeea6619a0ed4f37138661c49339b21361d397 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 19 May 2015 16:16:01 +0200 Subject: target: Simplify LUN shutdown code Instead of starting a thread from transport_clear_lun_ref() that waits for LUN shutdown, wait in that function for LUN shutdown to finish. Additionally, change the return type of transport_clear_lun_ref() from int to void. Signed-off-by: Bart Van Assche Reviewed-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_device.c | 1 - drivers/target/target_core_internal.h | 2 +- drivers/target/target_core_tpg.c | 2 -- drivers/target/target_core_transport.c | 23 +---------------------- include/target/target_core_base.h | 1 - 5 files changed, 2 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 22f1e180d8ee..1e4485b1849d 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -928,7 +928,6 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name) xcopy_lun = &dev->xcopy_lun; xcopy_lun->lun_se_dev = dev; - init_completion(&xcopy_lun->lun_shutdown_comp); spin_lock_init(&xcopy_lun->lun_sep_lock); init_completion(&xcopy_lun->lun_ref_comp); diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index 01181aed67dc..23f992ed7cae 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -108,7 +108,7 @@ int transport_dump_vpd_assoc(struct t10_vpd *, unsigned char *, int); int transport_dump_vpd_ident_type(struct t10_vpd *, unsigned char *, int); int transport_dump_vpd_ident(struct t10_vpd *, unsigned char *, int); bool target_stop_cmd(struct se_cmd *cmd, unsigned long *flags); -int transport_clear_lun_ref(struct se_lun *); +void transport_clear_lun_ref(struct se_lun *); void transport_send_task_abort(struct se_cmd *); sense_reason_t target_cmd_size_check(struct se_cmd *cmd, unsigned int size); void target_qf_do_work(struct work_struct *work); diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index 91f8ddb6d783..fd531fcf3191 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -494,7 +494,6 @@ static int core_tpg_setup_virtual_lun0(struct se_portal_group *se_tpg) lun->unpacked_lun = 0; atomic_set(&lun->lun_acl_count, 0); - init_completion(&lun->lun_shutdown_comp); spin_lock_init(&lun->lun_sep_lock); init_completion(&lun->lun_ref_comp); @@ -606,7 +605,6 @@ struct se_lun *core_tpg_alloc_lun( lun->unpacked_lun = unpacked_lun; lun->lun_link_magic = SE_LUN_LINK_MAGIC; atomic_set(&lun->lun_acl_count, 0); - init_completion(&lun->lun_shutdown_comp); spin_lock_init(&lun->lun_sep_lock); init_completion(&lun->lun_ref_comp); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 965a308e10a5..7c0518a28186 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2596,31 +2596,10 @@ void target_wait_for_sess_cmds(struct se_session *se_sess) } EXPORT_SYMBOL(target_wait_for_sess_cmds); -static int transport_clear_lun_ref_thread(void *p) +void transport_clear_lun_ref(struct se_lun *lun) { - struct se_lun *lun = p; - percpu_ref_kill(&lun->lun_ref); - wait_for_completion(&lun->lun_ref_comp); - complete(&lun->lun_shutdown_comp); - - return 0; -} - -int transport_clear_lun_ref(struct se_lun *lun) -{ - struct task_struct *kt; - - kt = kthread_run(transport_clear_lun_ref_thread, lun, - "tcm_cl_%u", lun->unpacked_lun); - if (IS_ERR(kt)) { - pr_err("Unable to start clear_lun thread\n"); - return PTR_ERR(kt); - } - wait_for_completion(&lun->lun_shutdown_comp); - - return 0; } /** diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 03e2ee8f8337..ee7abdd6b7a2 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -707,7 +707,6 @@ struct se_lun { u32 lun_index; atomic_t lun_acl_count; spinlock_t lun_sep_lock; - struct completion lun_shutdown_comp; struct se_device *lun_se_dev; struct se_port *lun_sep; struct config_group lun_group; -- cgit v1.2.3-70-g09d2 From adf653f92f38e80a78bb77e912d49bcc8055330f Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 25 May 2015 21:33:08 -0700 Subject: target: Subsume se_port + t10_alua_tg_pt_gp_member into se_lun This patch eliminates all se_port + t10_alua_tg_pt_gp_member usage, and converts current users to direct se_lun pointer dereference. This includes the removal of core_export_port(), core_release_port() core_dev_export() and core_dev_unexport(). Along with conversion of special case se_lun pointer dereference within PR ALL_TG_PT=1 and ALUA access state transition UNIT_ATTENTION handling. Also, update core_enable_device_list_for_node() to reference the new per se_lun->lun_deve_list when creating a new entry, or replacing an existing one via RCU. Signed-off-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_alua.c | 394 ++++++++++----------------- drivers/target/target_core_alua.h | 14 +- drivers/target/target_core_configfs.c | 11 +- drivers/target/target_core_device.c | 179 ++---------- drivers/target/target_core_fabric_configfs.c | 32 +-- drivers/target/target_core_internal.h | 12 +- drivers/target/target_core_pr.c | 56 ++-- drivers/target/target_core_spc.c | 48 ++-- drivers/target/target_core_stat.c | 299 ++++++++------------ drivers/target/target_core_tpg.c | 95 ++++--- drivers/target/target_core_transport.c | 34 +-- drivers/target/target_core_xcopy.c | 17 +- include/target/target_core_base.h | 74 +++-- 13 files changed, 458 insertions(+), 807 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 53cdfabac861..1109c2833fe6 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -43,11 +43,13 @@ static sense_reason_t core_alua_check_transition(int state, int valid, int *primary); static int core_alua_set_tg_pt_secondary_state( - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, - struct se_port *port, int explicit, int offline); + struct se_lun *lun, int explicit, int offline); static char *core_alua_dump_state(int state); +static void __target_attach_tg_pt_gp(struct se_lun *lun, + struct t10_alua_tg_pt_gp *tg_pt_gp); + static u16 alua_lu_gps_counter; static u32 alua_lu_gps_count; @@ -145,9 +147,8 @@ sense_reason_t target_emulate_report_target_port_groups(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; - struct se_port *port; struct t10_alua_tg_pt_gp *tg_pt_gp; - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; + struct se_lun *lun; unsigned char *buf; u32 rd_len = 0, off; int ext_hdr = (cmd->t_task_cdb[1] & 0x20); @@ -222,9 +223,8 @@ target_emulate_report_target_port_groups(struct se_cmd *cmd) rd_len += 8; spin_lock(&tg_pt_gp->tg_pt_gp_lock); - list_for_each_entry(tg_pt_gp_mem, &tg_pt_gp->tg_pt_gp_mem_list, - tg_pt_gp_mem_list) { - port = tg_pt_gp_mem->tg_pt; + list_for_each_entry(lun, &tg_pt_gp->tg_pt_gp_lun_list, + lun_tg_pt_gp_link) { /* * Start Target Port descriptor format * @@ -234,8 +234,8 @@ target_emulate_report_target_port_groups(struct se_cmd *cmd) /* * Set RELATIVE TARGET PORT IDENTIFIER */ - buf[off++] = ((port->sep_rtpi >> 8) & 0xff); - buf[off++] = (port->sep_rtpi & 0xff); + buf[off++] = ((lun->lun_rtpi >> 8) & 0xff); + buf[off++] = (lun->lun_rtpi & 0xff); rd_len += 4; } spin_unlock(&tg_pt_gp->tg_pt_gp_lock); @@ -259,15 +259,11 @@ target_emulate_report_target_port_groups(struct se_cmd *cmd) * this CDB was received upon to determine this value individually * for ALUA target port group. */ - port = cmd->se_lun->lun_sep; - tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; - if (tg_pt_gp_mem) { - spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; - if (tg_pt_gp) - buf[5] = tg_pt_gp->tg_pt_gp_implicit_trans_secs; - spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - } + spin_lock(&cmd->se_lun->lun_tg_pt_gp_lock); + tg_pt_gp = cmd->se_lun->lun_tg_pt_gp; + if (tg_pt_gp) + buf[5] = tg_pt_gp->tg_pt_gp_implicit_trans_secs; + spin_unlock(&cmd->se_lun->lun_tg_pt_gp_lock); } transport_kunmap_data_sg(cmd); @@ -284,10 +280,9 @@ sense_reason_t target_emulate_set_target_port_groups(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; - struct se_port *port, *l_port = cmd->se_lun->lun_sep; + struct se_lun *l_lun = cmd->se_lun; struct se_node_acl *nacl = cmd->se_sess->se_node_acl; struct t10_alua_tg_pt_gp *tg_pt_gp = NULL, *l_tg_pt_gp; - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, *l_tg_pt_gp_mem; unsigned char *buf; unsigned char *ptr; sense_reason_t rc = TCM_NO_SENSE; @@ -295,9 +290,6 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd) int alua_access_state, primary = 0, valid_states; u16 tg_pt_id, rtpi; - if (!l_port) - return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - if (cmd->data_length < 4) { pr_warn("SET TARGET PORT GROUPS parameter list length %u too" " small\n", cmd->data_length); @@ -312,29 +304,24 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd) * Determine if explicit ALUA via SET_TARGET_PORT_GROUPS is allowed * for the local tg_pt_gp. */ - l_tg_pt_gp_mem = l_port->sep_alua_tg_pt_gp_mem; - if (!l_tg_pt_gp_mem) { - pr_err("Unable to access l_port->sep_alua_tg_pt_gp_mem\n"); - rc = TCM_UNSUPPORTED_SCSI_OPCODE; - goto out; - } - spin_lock(&l_tg_pt_gp_mem->tg_pt_gp_mem_lock); - l_tg_pt_gp = l_tg_pt_gp_mem->tg_pt_gp; + spin_lock(&l_lun->lun_tg_pt_gp_lock); + l_tg_pt_gp = l_lun->lun_tg_pt_gp; if (!l_tg_pt_gp) { - spin_unlock(&l_tg_pt_gp_mem->tg_pt_gp_mem_lock); - pr_err("Unable to access *l_tg_pt_gp_mem->tg_pt_gp\n"); + spin_unlock(&l_lun->lun_tg_pt_gp_lock); + pr_err("Unable to access l_lun->tg_pt_gp\n"); rc = TCM_UNSUPPORTED_SCSI_OPCODE; goto out; } - spin_unlock(&l_tg_pt_gp_mem->tg_pt_gp_mem_lock); if (!(l_tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_EXPLICIT_ALUA)) { + spin_unlock(&l_lun->lun_tg_pt_gp_lock); pr_debug("Unable to process SET_TARGET_PORT_GROUPS" " while TPGS_EXPLICIT_ALUA is disabled\n"); rc = TCM_UNSUPPORTED_SCSI_OPCODE; goto out; } valid_states = l_tg_pt_gp->tg_pt_gp_alua_supported_states; + spin_unlock(&l_lun->lun_tg_pt_gp_lock); ptr = &buf[4]; /* Skip over RESERVED area in header */ @@ -396,7 +383,7 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd) spin_unlock(&dev->t10_alua.tg_pt_gps_lock); if (!core_alua_do_port_transition(tg_pt_gp, - dev, l_port, nacl, + dev, l_lun, nacl, alua_access_state, 1)) found = true; @@ -406,6 +393,8 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd) } spin_unlock(&dev->t10_alua.tg_pt_gps_lock); } else { + struct se_lun *lun; + /* * Extract the RELATIVE TARGET PORT IDENTIFIER to identify * the Target Port in question for the the incoming @@ -417,17 +406,16 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd) * for the struct se_device storage object. */ spin_lock(&dev->se_port_lock); - list_for_each_entry(port, &dev->dev_sep_list, - sep_list) { - if (port->sep_rtpi != rtpi) + list_for_each_entry(lun, &dev->dev_sep_list, + lun_dev_link) { + if (lun->lun_rtpi != rtpi) continue; - tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; - + // XXX: racy unlock spin_unlock(&dev->se_port_lock); if (!core_alua_set_tg_pt_secondary_state( - tg_pt_gp_mem, port, 1, 1)) + lun, 1, 1)) found = true; spin_lock(&dev->se_port_lock); @@ -696,9 +684,7 @@ target_alua_state_check(struct se_cmd *cmd) struct se_device *dev = cmd->se_dev; unsigned char *cdb = cmd->t_task_cdb; struct se_lun *lun = cmd->se_lun; - struct se_port *port = lun->lun_sep; struct t10_alua_tg_pt_gp *tg_pt_gp; - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; int out_alua_state, nonop_delay_msecs; if (dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE) @@ -706,33 +692,27 @@ target_alua_state_check(struct se_cmd *cmd) if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH) return 0; - if (!port) - return 0; /* * First, check for a struct se_port specific secondary ALUA target port * access state: OFFLINE */ - if (atomic_read(&port->sep_tg_pt_secondary_offline)) { + if (atomic_read(&lun->lun_tg_pt_secondary_offline)) { pr_debug("ALUA: Got secondary offline status for local" " target port\n"); set_ascq(cmd, ASCQ_04H_ALUA_OFFLINE); return TCM_CHECK_CONDITION_NOT_READY; } - /* - * Second, obtain the struct t10_alua_tg_pt_gp_member pointer to the - * ALUA target port group, to obtain current ALUA access state. - * Otherwise look for the underlying struct se_device association with - * a ALUA logical unit group. - */ - tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; - if (!tg_pt_gp_mem) + + if (!lun->lun_tg_pt_gp) return 0; - spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; + spin_lock(&lun->lun_tg_pt_gp_lock); + tg_pt_gp = lun->lun_tg_pt_gp; out_alua_state = atomic_read(&tg_pt_gp->tg_pt_gp_alua_access_state); nonop_delay_msecs = tg_pt_gp->tg_pt_gp_nonop_delay_msecs; - spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + + // XXX: keeps using tg_pt_gp witout reference after unlock + spin_unlock(&lun->lun_tg_pt_gp_lock); /* * Process ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED in a separate conditional * statement so the compiler knows explicitly to check this case first. @@ -764,7 +744,7 @@ target_alua_state_check(struct se_cmd *cmd) break; /* * OFFLINE is a secondary ALUA target port group access state, that is - * handled above with struct se_port->sep_tg_pt_secondary_offline=1 + * handled above with struct se_lun->lun_tg_pt_secondary_offline=1 */ case ALUA_ACCESS_STATE_OFFLINE: default: @@ -906,10 +886,6 @@ int core_alua_check_nonop_delay( } EXPORT_SYMBOL(core_alua_check_nonop_delay); -/* - * Called with tg_pt_gp->tg_pt_gp_md_mutex or tg_pt_gp_mem->sep_tg_pt_md_mutex - * - */ static int core_alua_write_tpg_metadata( const char *path, unsigned char *md_buf, @@ -971,16 +947,14 @@ static void core_alua_do_transition_tg_pt_work(struct work_struct *work) struct t10_alua_tg_pt_gp, tg_pt_gp_transition_work.work); struct se_device *dev = tg_pt_gp->tg_pt_gp_dev; struct se_dev_entry *se_deve; + struct se_lun *lun; struct se_lun_acl *lacl; - struct se_port *port; - struct t10_alua_tg_pt_gp_member *mem; bool explicit = (tg_pt_gp->tg_pt_gp_alua_access_status == ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG); spin_lock(&tg_pt_gp->tg_pt_gp_lock); - list_for_each_entry(mem, &tg_pt_gp->tg_pt_gp_mem_list, - tg_pt_gp_mem_list) { - port = mem->tg_pt; + list_for_each_entry(lun, &tg_pt_gp->tg_pt_gp_lun_list, + lun_tg_pt_gp_link) { /* * After an implicit target port asymmetric access state * change, a device server shall establish a unit attention @@ -995,14 +969,13 @@ static void core_alua_do_transition_tg_pt_work(struct work_struct *work) * every I_T nexus other than the I_T nexus on which the SET * TARGET PORT GROUPS command */ - atomic_inc_mb(&mem->tg_pt_gp_mem_ref_cnt); + atomic_inc_mb(&lun->lun_active); spin_unlock(&tg_pt_gp->tg_pt_gp_lock); - spin_lock_bh(&port->sep_alua_lock); - list_for_each_entry(se_deve, &port->sep_alua_list, - alua_port_list) { + spin_lock_bh(&lun->lun_deve_lock); + list_for_each_entry(se_deve, &lun->lun_deve_list, lun_link) { lacl = rcu_dereference_check(se_deve->se_lun_acl, - lockdep_is_held(&port->sep_alua_lock)); + lockdep_is_held(&lun->lun_deve_lock)); /* * se_deve->se_lun_acl pointer may be NULL for a * entry created without explicit Node+MappedLUN ACLs @@ -1014,18 +987,18 @@ static void core_alua_do_transition_tg_pt_work(struct work_struct *work) ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG) && (tg_pt_gp->tg_pt_gp_alua_nacl != NULL) && (tg_pt_gp->tg_pt_gp_alua_nacl == lacl->se_lun_nacl) && - (tg_pt_gp->tg_pt_gp_alua_port != NULL) && - (tg_pt_gp->tg_pt_gp_alua_port == port)) + (tg_pt_gp->tg_pt_gp_alua_lun != NULL) && + (tg_pt_gp->tg_pt_gp_alua_lun == lun)) continue; core_scsi3_ua_allocate(lacl->se_lun_nacl, se_deve->mapped_lun, 0x2A, ASCQ_2AH_ASYMMETRIC_ACCESS_STATE_CHANGED); } - spin_unlock_bh(&port->sep_alua_lock); + spin_unlock_bh(&lun->lun_deve_lock); spin_lock(&tg_pt_gp->tg_pt_gp_lock); - atomic_dec_mb(&mem->tg_pt_gp_mem_ref_cnt); + atomic_dec_mb(&lun->lun_active); } spin_unlock(&tg_pt_gp->tg_pt_gp_lock); /* @@ -1143,7 +1116,7 @@ static int core_alua_do_transition_tg_pt( int core_alua_do_port_transition( struct t10_alua_tg_pt_gp *l_tg_pt_gp, struct se_device *l_dev, - struct se_port *l_port, + struct se_lun *l_lun, struct se_node_acl *l_nacl, int new_state, int explicit) @@ -1173,7 +1146,7 @@ int core_alua_do_port_transition( * core_alua_do_transition_tg_pt() will always return * success. */ - l_tg_pt_gp->tg_pt_gp_alua_port = l_port; + l_tg_pt_gp->tg_pt_gp_alua_lun = l_lun; l_tg_pt_gp->tg_pt_gp_alua_nacl = l_nacl; rc = core_alua_do_transition_tg_pt(l_tg_pt_gp, new_state, explicit); @@ -1212,10 +1185,10 @@ int core_alua_do_port_transition( continue; if (l_tg_pt_gp == tg_pt_gp) { - tg_pt_gp->tg_pt_gp_alua_port = l_port; + tg_pt_gp->tg_pt_gp_alua_lun = l_lun; tg_pt_gp->tg_pt_gp_alua_nacl = l_nacl; } else { - tg_pt_gp->tg_pt_gp_alua_port = NULL; + tg_pt_gp->tg_pt_gp_alua_lun = NULL; tg_pt_gp->tg_pt_gp_alua_nacl = NULL; } atomic_inc_mb(&tg_pt_gp->tg_pt_gp_ref_cnt); @@ -1252,22 +1225,20 @@ int core_alua_do_port_transition( return rc; } -/* - * Called with tg_pt_gp_mem->sep_tg_pt_md_mutex held - */ -static int core_alua_update_tpg_secondary_metadata( - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, - struct se_port *port) +static int core_alua_update_tpg_secondary_metadata(struct se_lun *lun) { + struct se_portal_group *se_tpg = lun->lun_tpg; unsigned char *md_buf; - struct se_portal_group *se_tpg = port->sep_tpg; char path[ALUA_METADATA_PATH_LEN], wwn[ALUA_SECONDARY_METADATA_WWN_LEN]; int len, rc; + mutex_lock(&lun->lun_tg_pt_md_mutex); + md_buf = kzalloc(ALUA_MD_BUF_LEN, GFP_KERNEL); if (!md_buf) { pr_err("Unable to allocate buf for ALUA metadata\n"); - return -ENOMEM; + rc = -ENOMEM; + goto out_unlock; } memset(path, 0, ALUA_METADATA_PATH_LEN); @@ -1282,32 +1253,33 @@ static int core_alua_update_tpg_secondary_metadata( len = snprintf(md_buf, ALUA_MD_BUF_LEN, "alua_tg_pt_offline=%d\n" "alua_tg_pt_status=0x%02x\n", - atomic_read(&port->sep_tg_pt_secondary_offline), - port->sep_tg_pt_secondary_stat); + atomic_read(&lun->lun_tg_pt_secondary_offline), + lun->lun_tg_pt_secondary_stat); snprintf(path, ALUA_METADATA_PATH_LEN, "/var/target/alua/%s/%s/lun_%u", se_tpg->se_tpg_tfo->get_fabric_name(), wwn, - port->sep_lun->unpacked_lun); + lun->unpacked_lun); rc = core_alua_write_tpg_metadata(path, md_buf, len); kfree(md_buf); +out_unlock: + mutex_unlock(&lun->lun_tg_pt_md_mutex); return rc; } static int core_alua_set_tg_pt_secondary_state( - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, - struct se_port *port, + struct se_lun *lun, int explicit, int offline) { struct t10_alua_tg_pt_gp *tg_pt_gp; int trans_delay_msecs; - spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; + spin_lock(&lun->lun_tg_pt_gp_lock); + tg_pt_gp = lun->lun_tg_pt_gp; if (!tg_pt_gp) { - spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + spin_unlock(&lun->lun_tg_pt_gp_lock); pr_err("Unable to complete secondary state" " transition\n"); return -EINVAL; @@ -1315,14 +1287,14 @@ static int core_alua_set_tg_pt_secondary_state( trans_delay_msecs = tg_pt_gp->tg_pt_gp_trans_delay_msecs; /* * Set the secondary ALUA target port access state to OFFLINE - * or release the previously secondary state for struct se_port + * or release the previously secondary state for struct se_lun */ if (offline) - atomic_set(&port->sep_tg_pt_secondary_offline, 1); + atomic_set(&lun->lun_tg_pt_secondary_offline, 1); else - atomic_set(&port->sep_tg_pt_secondary_offline, 0); + atomic_set(&lun->lun_tg_pt_secondary_offline, 0); - port->sep_tg_pt_secondary_stat = (explicit) ? + lun->lun_tg_pt_secondary_stat = (explicit) ? ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG : ALUA_STATUS_ALTERED_BY_IMPLICIT_ALUA; @@ -1331,7 +1303,7 @@ static int core_alua_set_tg_pt_secondary_state( "implicit", config_item_name(&tg_pt_gp->tg_pt_gp_group.cg_item), tg_pt_gp->tg_pt_gp_id, (offline) ? "OFFLINE" : "ONLINE"); - spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + spin_unlock(&lun->lun_tg_pt_gp_lock); /* * Do the optional transition delay after we set the secondary * ALUA access state. @@ -1342,11 +1314,8 @@ static int core_alua_set_tg_pt_secondary_state( * See if we need to update the ALUA fabric port metadata for * secondary state and status */ - if (port->sep_tg_pt_secondary_write_md) { - mutex_lock(&port->sep_tg_pt_md_mutex); - core_alua_update_tpg_secondary_metadata(tg_pt_gp_mem, port); - mutex_unlock(&port->sep_tg_pt_md_mutex); - } + if (lun->lun_tg_pt_secondary_write_md) + core_alua_update_tpg_secondary_metadata(lun); return 0; } @@ -1700,7 +1669,7 @@ struct t10_alua_tg_pt_gp *core_alua_allocate_tg_pt_gp(struct se_device *dev, return NULL; } INIT_LIST_HEAD(&tg_pt_gp->tg_pt_gp_list); - INIT_LIST_HEAD(&tg_pt_gp->tg_pt_gp_mem_list); + INIT_LIST_HEAD(&tg_pt_gp->tg_pt_gp_lun_list); mutex_init(&tg_pt_gp->tg_pt_gp_md_mutex); spin_lock_init(&tg_pt_gp->tg_pt_gp_lock); atomic_set(&tg_pt_gp->tg_pt_gp_ref_cnt, 0); @@ -1794,32 +1763,11 @@ again: return 0; } -struct t10_alua_tg_pt_gp_member *core_alua_allocate_tg_pt_gp_mem( - struct se_port *port) -{ - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; - - tg_pt_gp_mem = kmem_cache_zalloc(t10_alua_tg_pt_gp_mem_cache, - GFP_KERNEL); - if (!tg_pt_gp_mem) { - pr_err("Unable to allocate struct t10_alua_tg_pt_gp_member\n"); - return ERR_PTR(-ENOMEM); - } - INIT_LIST_HEAD(&tg_pt_gp_mem->tg_pt_gp_mem_list); - spin_lock_init(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - atomic_set(&tg_pt_gp_mem->tg_pt_gp_mem_ref_cnt, 0); - - tg_pt_gp_mem->tg_pt = port; - port->sep_alua_tg_pt_gp_mem = tg_pt_gp_mem; - - return tg_pt_gp_mem; -} - void core_alua_free_tg_pt_gp( struct t10_alua_tg_pt_gp *tg_pt_gp) { struct se_device *dev = tg_pt_gp->tg_pt_gp_dev; - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, *tg_pt_gp_mem_tmp; + struct se_lun *lun, *next; /* * Once we have reached this point, config_item_put() has already @@ -1850,30 +1798,24 @@ void core_alua_free_tg_pt_gp( * struct se_port. */ spin_lock(&tg_pt_gp->tg_pt_gp_lock); - list_for_each_entry_safe(tg_pt_gp_mem, tg_pt_gp_mem_tmp, - &tg_pt_gp->tg_pt_gp_mem_list, tg_pt_gp_mem_list) { - if (tg_pt_gp_mem->tg_pt_gp_assoc) { - list_del(&tg_pt_gp_mem->tg_pt_gp_mem_list); - tg_pt_gp->tg_pt_gp_members--; - tg_pt_gp_mem->tg_pt_gp_assoc = 0; - } + list_for_each_entry_safe(lun, next, + &tg_pt_gp->tg_pt_gp_lun_list, lun_tg_pt_gp_link) { + list_del_init(&lun->lun_tg_pt_gp_link); + tg_pt_gp->tg_pt_gp_members--; + spin_unlock(&tg_pt_gp->tg_pt_gp_lock); /* - * tg_pt_gp_mem is associated with a single - * se_port->sep_alua_tg_pt_gp_mem, and is released via - * core_alua_free_tg_pt_gp_mem(). - * * If the passed tg_pt_gp does NOT match the default_tg_pt_gp, * assume we want to re-associate a given tg_pt_gp_mem with * default_tg_pt_gp. */ - spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + spin_lock(&lun->lun_tg_pt_gp_lock); if (tg_pt_gp != dev->t10_alua.default_tg_pt_gp) { - __core_alua_attach_tg_pt_gp_mem(tg_pt_gp_mem, + __target_attach_tg_pt_gp(lun, dev->t10_alua.default_tg_pt_gp); } else - tg_pt_gp_mem->tg_pt_gp = NULL; - spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + lun->lun_tg_pt_gp = NULL; + spin_unlock(&lun->lun_tg_pt_gp_lock); spin_lock(&tg_pt_gp->tg_pt_gp_lock); } @@ -1882,35 +1824,6 @@ void core_alua_free_tg_pt_gp( kmem_cache_free(t10_alua_tg_pt_gp_cache, tg_pt_gp); } -void core_alua_free_tg_pt_gp_mem(struct se_port *port) -{ - struct t10_alua_tg_pt_gp *tg_pt_gp; - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; - - tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; - if (!tg_pt_gp_mem) - return; - - while (atomic_read(&tg_pt_gp_mem->tg_pt_gp_mem_ref_cnt)) - cpu_relax(); - - spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; - if (tg_pt_gp) { - spin_lock(&tg_pt_gp->tg_pt_gp_lock); - if (tg_pt_gp_mem->tg_pt_gp_assoc) { - list_del(&tg_pt_gp_mem->tg_pt_gp_mem_list); - tg_pt_gp->tg_pt_gp_members--; - tg_pt_gp_mem->tg_pt_gp_assoc = 0; - } - spin_unlock(&tg_pt_gp->tg_pt_gp_lock); - tg_pt_gp_mem->tg_pt_gp = NULL; - } - spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - - kmem_cache_free(t10_alua_tg_pt_gp_mem_cache, tg_pt_gp_mem); -} - static struct t10_alua_tg_pt_gp *core_alua_get_tg_pt_gp_by_name( struct se_device *dev, const char *name) { @@ -1944,50 +1857,58 @@ static void core_alua_put_tg_pt_gp_from_name( spin_unlock(&dev->t10_alua.tg_pt_gps_lock); } -/* - * Called with struct t10_alua_tg_pt_gp_member->tg_pt_gp_mem_lock held - */ -void __core_alua_attach_tg_pt_gp_mem( - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, - struct t10_alua_tg_pt_gp *tg_pt_gp) +static void __target_attach_tg_pt_gp(struct se_lun *lun, + struct t10_alua_tg_pt_gp *tg_pt_gp) { + assert_spin_locked(&lun->lun_tg_pt_gp_lock); + spin_lock(&tg_pt_gp->tg_pt_gp_lock); - tg_pt_gp_mem->tg_pt_gp = tg_pt_gp; - tg_pt_gp_mem->tg_pt_gp_assoc = 1; - list_add_tail(&tg_pt_gp_mem->tg_pt_gp_mem_list, - &tg_pt_gp->tg_pt_gp_mem_list); + lun->lun_tg_pt_gp = tg_pt_gp; + list_add_tail(&lun->lun_tg_pt_gp_link, &tg_pt_gp->tg_pt_gp_lun_list); tg_pt_gp->tg_pt_gp_members++; spin_unlock(&tg_pt_gp->tg_pt_gp_lock); } -/* - * Called with struct t10_alua_tg_pt_gp_member->tg_pt_gp_mem_lock held - */ -static void __core_alua_drop_tg_pt_gp_mem( - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, - struct t10_alua_tg_pt_gp *tg_pt_gp) +void target_attach_tg_pt_gp(struct se_lun *lun, + struct t10_alua_tg_pt_gp *tg_pt_gp) +{ + spin_lock(&lun->lun_tg_pt_gp_lock); + __target_attach_tg_pt_gp(lun, tg_pt_gp); + spin_unlock(&lun->lun_tg_pt_gp_lock); +} + +static void __target_detach_tg_pt_gp(struct se_lun *lun, + struct t10_alua_tg_pt_gp *tg_pt_gp) { + assert_spin_locked(&lun->lun_tg_pt_gp_lock); + spin_lock(&tg_pt_gp->tg_pt_gp_lock); - list_del(&tg_pt_gp_mem->tg_pt_gp_mem_list); - tg_pt_gp_mem->tg_pt_gp = NULL; - tg_pt_gp_mem->tg_pt_gp_assoc = 0; + list_del_init(&lun->lun_tg_pt_gp_link); tg_pt_gp->tg_pt_gp_members--; spin_unlock(&tg_pt_gp->tg_pt_gp_lock); + + lun->lun_tg_pt_gp = NULL; } -ssize_t core_alua_show_tg_pt_gp_info(struct se_port *port, char *page) +void target_detach_tg_pt_gp(struct se_lun *lun) +{ + struct t10_alua_tg_pt_gp *tg_pt_gp; + + spin_lock(&lun->lun_tg_pt_gp_lock); + tg_pt_gp = lun->lun_tg_pt_gp; + if (tg_pt_gp) + __target_detach_tg_pt_gp(lun, tg_pt_gp); + spin_unlock(&lun->lun_tg_pt_gp_lock); +} + +ssize_t core_alua_show_tg_pt_gp_info(struct se_lun *lun, char *page) { struct config_item *tg_pt_ci; struct t10_alua_tg_pt_gp *tg_pt_gp; - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; ssize_t len = 0; - tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; - if (!tg_pt_gp_mem) - return len; - - spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; + spin_lock(&lun->lun_tg_pt_gp_lock); + tg_pt_gp = lun->lun_tg_pt_gp; if (tg_pt_gp) { tg_pt_ci = &tg_pt_gp->tg_pt_gp_group.cg_item; len += sprintf(page, "TG Port Alias: %s\nTG Port Group ID:" @@ -1999,34 +1920,29 @@ ssize_t core_alua_show_tg_pt_gp_info(struct se_port *port, char *page) &tg_pt_gp->tg_pt_gp_alua_access_state)), core_alua_dump_status( tg_pt_gp->tg_pt_gp_alua_access_status), - (atomic_read(&port->sep_tg_pt_secondary_offline)) ? + atomic_read(&lun->lun_tg_pt_secondary_offline) ? "Offline" : "None", - core_alua_dump_status(port->sep_tg_pt_secondary_stat)); + core_alua_dump_status(lun->lun_tg_pt_secondary_stat)); } - spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + spin_unlock(&lun->lun_tg_pt_gp_lock); return len; } ssize_t core_alua_store_tg_pt_gp_info( - struct se_port *port, + struct se_lun *lun, const char *page, size_t count) { - struct se_portal_group *tpg; - struct se_lun *lun; - struct se_device *dev = port->sep_lun->lun_se_dev; + struct se_portal_group *tpg = lun->lun_tpg; + struct se_device *dev = lun->lun_se_dev; struct t10_alua_tg_pt_gp *tg_pt_gp = NULL, *tg_pt_gp_new = NULL; - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; unsigned char buf[TG_PT_GROUP_NAME_BUF]; int move = 0; - tpg = port->sep_tpg; - lun = port->sep_lun; - - tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; - if (!tg_pt_gp_mem) - return 0; + if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH || + (dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) + return -ENODEV; if (count > TG_PT_GROUP_NAME_BUF) { pr_err("ALUA Target Port Group alias too large!\n"); @@ -2050,8 +1966,8 @@ ssize_t core_alua_store_tg_pt_gp_info( return -ENODEV; } - spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; + spin_lock(&lun->lun_tg_pt_gp_lock); + tg_pt_gp = lun->lun_tg_pt_gp; if (tg_pt_gp) { /* * Clearing an existing tg_pt_gp association, and replacing @@ -2069,24 +1985,19 @@ ssize_t core_alua_store_tg_pt_gp_info( &tg_pt_gp->tg_pt_gp_group.cg_item), tg_pt_gp->tg_pt_gp_id); - __core_alua_drop_tg_pt_gp_mem(tg_pt_gp_mem, tg_pt_gp); - __core_alua_attach_tg_pt_gp_mem(tg_pt_gp_mem, + __target_detach_tg_pt_gp(lun, tg_pt_gp); + __target_attach_tg_pt_gp(lun, dev->t10_alua.default_tg_pt_gp); - spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + spin_unlock(&lun->lun_tg_pt_gp_lock); return count; } - /* - * Removing existing association of tg_pt_gp_mem with tg_pt_gp - */ - __core_alua_drop_tg_pt_gp_mem(tg_pt_gp_mem, tg_pt_gp); + __target_detach_tg_pt_gp(lun, tg_pt_gp); move = 1; } - /* - * Associate tg_pt_gp_mem with tg_pt_gp_new. - */ - __core_alua_attach_tg_pt_gp_mem(tg_pt_gp_mem, tg_pt_gp_new); - spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + + __target_attach_tg_pt_gp(lun, tg_pt_gp_new); + spin_unlock(&lun->lun_tg_pt_gp_lock); pr_debug("Target_Core_ConfigFS: %s %s/tpgt_%hu/%s to ALUA" " Target Port Group: alua/%s, ID: %hu\n", (move) ? "Moving" : "Adding", tpg->se_tpg_tfo->tpg_get_wwn(tpg), @@ -2269,11 +2180,8 @@ ssize_t core_alua_store_preferred_bit( ssize_t core_alua_show_offline_bit(struct se_lun *lun, char *page) { - if (!lun->lun_sep) - return -ENODEV; - return sprintf(page, "%d\n", - atomic_read(&lun->lun_sep->sep_tg_pt_secondary_offline)); + atomic_read(&lun->lun_tg_pt_secondary_offline)); } ssize_t core_alua_store_offline_bit( @@ -2281,11 +2189,12 @@ ssize_t core_alua_store_offline_bit( const char *page, size_t count) { - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; + struct se_device *dev = lun->lun_se_dev; unsigned long tmp; int ret; - if (!lun->lun_sep) + if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH || + (dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) return -ENODEV; ret = kstrtoul(page, 0, &tmp); @@ -2298,14 +2207,8 @@ ssize_t core_alua_store_offline_bit( tmp); return -EINVAL; } - tg_pt_gp_mem = lun->lun_sep->sep_alua_tg_pt_gp_mem; - if (!tg_pt_gp_mem) { - pr_err("Unable to locate *tg_pt_gp_mem\n"); - return -EINVAL; - } - ret = core_alua_set_tg_pt_secondary_state(tg_pt_gp_mem, - lun->lun_sep, 0, (int)tmp); + ret = core_alua_set_tg_pt_secondary_state(lun, 0, (int)tmp); if (ret < 0) return -EINVAL; @@ -2316,7 +2219,7 @@ ssize_t core_alua_show_secondary_status( struct se_lun *lun, char *page) { - return sprintf(page, "%d\n", lun->lun_sep->sep_tg_pt_secondary_stat); + return sprintf(page, "%d\n", lun->lun_tg_pt_secondary_stat); } ssize_t core_alua_store_secondary_status( @@ -2339,7 +2242,7 @@ ssize_t core_alua_store_secondary_status( tmp); return -EINVAL; } - lun->lun_sep->sep_tg_pt_secondary_stat = (int)tmp; + lun->lun_tg_pt_secondary_stat = (int)tmp; return count; } @@ -2348,8 +2251,7 @@ ssize_t core_alua_show_secondary_write_metadata( struct se_lun *lun, char *page) { - return sprintf(page, "%d\n", - lun->lun_sep->sep_tg_pt_secondary_write_md); + return sprintf(page, "%d\n", lun->lun_tg_pt_secondary_write_md); } ssize_t core_alua_store_secondary_write_metadata( @@ -2370,7 +2272,7 @@ ssize_t core_alua_store_secondary_write_metadata( " %lu\n", tmp); return -EINVAL; } - lun->lun_sep->sep_tg_pt_secondary_write_md = (int)tmp; + lun->lun_tg_pt_secondary_write_md = (int)tmp; return count; } diff --git a/drivers/target/target_core_alua.h b/drivers/target/target_core_alua.h index 0a7d65e80404..9b250f9b33bf 100644 --- a/drivers/target/target_core_alua.h +++ b/drivers/target/target_core_alua.h @@ -85,7 +85,6 @@ extern struct kmem_cache *t10_alua_lu_gp_cache; extern struct kmem_cache *t10_alua_lu_gp_mem_cache; extern struct kmem_cache *t10_alua_tg_pt_gp_cache; -extern struct kmem_cache *t10_alua_tg_pt_gp_mem_cache; extern struct kmem_cache *t10_alua_lba_map_cache; extern struct kmem_cache *t10_alua_lba_map_mem_cache; @@ -94,7 +93,7 @@ extern sense_reason_t target_emulate_set_target_port_groups(struct se_cmd *); extern sense_reason_t target_emulate_report_referrals(struct se_cmd *); extern int core_alua_check_nonop_delay(struct se_cmd *); extern int core_alua_do_port_transition(struct t10_alua_tg_pt_gp *, - struct se_device *, struct se_port *, + struct se_device *, struct se_lun *, struct se_node_acl *, int, int); extern char *core_alua_dump_status(int); extern struct t10_alua_lba_map *core_alua_allocate_lba_map( @@ -117,14 +116,11 @@ extern void core_alua_drop_lu_gp_dev(struct se_device *); extern struct t10_alua_tg_pt_gp *core_alua_allocate_tg_pt_gp( struct se_device *, const char *, int); extern int core_alua_set_tg_pt_gp_id(struct t10_alua_tg_pt_gp *, u16); -extern struct t10_alua_tg_pt_gp_member *core_alua_allocate_tg_pt_gp_mem( - struct se_port *); extern void core_alua_free_tg_pt_gp(struct t10_alua_tg_pt_gp *); -extern void core_alua_free_tg_pt_gp_mem(struct se_port *); -extern void __core_alua_attach_tg_pt_gp_mem(struct t10_alua_tg_pt_gp_member *, - struct t10_alua_tg_pt_gp *); -extern ssize_t core_alua_show_tg_pt_gp_info(struct se_port *, char *); -extern ssize_t core_alua_store_tg_pt_gp_info(struct se_port *, const char *, +extern void target_detach_tg_pt_gp(struct se_lun *); +extern void target_attach_tg_pt_gp(struct se_lun *, struct t10_alua_tg_pt_gp *); +extern ssize_t core_alua_show_tg_pt_gp_info(struct se_lun *, char *); +extern ssize_t core_alua_store_tg_pt_gp_info(struct se_lun *, const char *, size_t); extern ssize_t core_alua_show_access_type(struct t10_alua_tg_pt_gp *, char *); extern ssize_t core_alua_store_access_type(struct t10_alua_tg_pt_gp *, diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 4313eea060ed..f97b969e6714 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -2889,21 +2889,16 @@ static ssize_t target_core_alua_tg_pt_gp_show_attr_members( struct t10_alua_tg_pt_gp *tg_pt_gp, char *page) { - struct se_port *port; - struct se_portal_group *tpg; struct se_lun *lun; - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; ssize_t len = 0, cur_len; unsigned char buf[TG_PT_GROUP_NAME_BUF]; memset(buf, 0, TG_PT_GROUP_NAME_BUF); spin_lock(&tg_pt_gp->tg_pt_gp_lock); - list_for_each_entry(tg_pt_gp_mem, &tg_pt_gp->tg_pt_gp_mem_list, - tg_pt_gp_mem_list) { - port = tg_pt_gp_mem->tg_pt; - tpg = port->sep_tpg; - lun = port->sep_lun; + list_for_each_entry(lun, &tg_pt_gp->tg_pt_gp_lun_list, + lun_tg_pt_gp_link) { + struct se_portal_group *tpg = lun->lun_tpg; cur_len = snprintf(buf, TG_PT_GROUP_NAME_BUF, "%s/%s/tpgt_%hu" "/%s\n", tpg->se_tpg_tfo->get_fabric_name(), diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 1e4485b1849d..8485e9a789fc 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -120,8 +120,8 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd, u32 unpacked_lun) (se_cmd->data_direction != DMA_NONE)) return TCM_WRITE_PROTECTED; - se_lun = &se_sess->se_tpg->tpg_virt_lun0; - se_cmd->se_lun = &se_sess->se_tpg->tpg_virt_lun0; + se_lun = se_sess->se_tpg->tpg_virt_lun0; + se_cmd->se_lun = se_sess->se_tpg->tpg_virt_lun0; se_cmd->orig_fe_lun = 0; se_cmd->se_cmd_flags |= SCF_SE_LUN_CMD; @@ -309,7 +309,6 @@ int core_enable_device_list_for_node( struct se_node_acl *nacl, struct se_portal_group *tpg) { - struct se_port *port = lun->lun_sep; struct se_dev_entry *orig, *new; new = kzalloc(sizeof(*new), GFP_KERNEL); @@ -320,8 +319,8 @@ int core_enable_device_list_for_node( atomic_set(&new->ua_count, 0); spin_lock_init(&new->ua_lock); - INIT_LIST_HEAD(&new->alua_port_list); INIT_LIST_HEAD(&new->ua_list); + INIT_LIST_HEAD(&new->lun_link); new->mapped_lun = mapped_lun; kref_init(&new->pr_kref); @@ -357,10 +356,10 @@ int core_enable_device_list_for_node( hlist_add_head_rcu(&new->link, &nacl->lun_entry_hlist); mutex_unlock(&nacl->lun_entry_mutex); - spin_lock_bh(&port->sep_alua_lock); - list_del(&orig->alua_port_list); - list_add_tail(&new->alua_port_list, &port->sep_alua_list); - spin_unlock_bh(&port->sep_alua_lock); + spin_lock_bh(&lun->lun_deve_lock); + list_del(&orig->lun_link); + list_add_tail(&new->lun_link, &lun->lun_deve_list); + spin_unlock_bh(&lun->lun_deve_lock); kref_put(&orig->pr_kref, target_pr_kref_release); wait_for_completion(&orig->pr_comp); @@ -374,9 +373,9 @@ int core_enable_device_list_for_node( hlist_add_head_rcu(&new->link, &nacl->lun_entry_hlist); mutex_unlock(&nacl->lun_entry_mutex); - spin_lock_bh(&port->sep_alua_lock); - list_add_tail(&new->alua_port_list, &port->sep_alua_list); - spin_unlock_bh(&port->sep_alua_lock); + spin_lock_bh(&lun->lun_deve_lock); + list_add_tail(&new->lun_link, &lun->lun_deve_list); + spin_unlock_bh(&lun->lun_deve_lock); return 0; } @@ -390,23 +389,22 @@ void core_disable_device_list_for_node( struct se_node_acl *nacl, struct se_portal_group *tpg) { - struct se_port *port = lun->lun_sep; /* * If the MappedLUN entry is being disabled, the entry in - * port->sep_alua_list must be removed now before clearing the + * lun->lun_deve_list must be removed now before clearing the * struct se_dev_entry pointers below as logic in * core_alua_do_transition_tg_pt() depends on these being present. * * deve->se_lun_acl will be NULL for demo-mode created LUNs * that have not been explicitly converted to MappedLUNs -> - * struct se_lun_acl, but we remove deve->alua_port_list from - * port->sep_alua_list. This also means that active UAs and + * struct se_lun_acl, but we remove deve->lun_link from + * lun->lun_deve_list. This also means that active UAs and * NodeACL context specific PR metadata for demo-mode * MappedLUN *deve will be released below.. */ - spin_lock_bh(&port->sep_alua_lock); - list_del(&orig->alua_port_list); - spin_unlock_bh(&port->sep_alua_lock); + spin_lock_bh(&lun->lun_deve_lock); + list_del(&orig->lun_link); + spin_unlock_bh(&lun->lun_deve_lock); /* * Disable struct se_dev_entry LUN ACL mapping */ @@ -458,27 +456,16 @@ void core_clear_lun_from_tpg(struct se_lun *lun, struct se_portal_group *tpg) mutex_unlock(&tpg->acl_node_mutex); } -static struct se_port *core_alloc_port(struct se_device *dev) +int core_alloc_rtpi(struct se_lun *lun, struct se_device *dev) { - struct se_port *port, *port_tmp; - - port = kzalloc(sizeof(struct se_port), GFP_KERNEL); - if (!port) { - pr_err("Unable to allocate struct se_port\n"); - return ERR_PTR(-ENOMEM); - } - INIT_LIST_HEAD(&port->sep_alua_list); - INIT_LIST_HEAD(&port->sep_list); - atomic_set(&port->sep_tg_pt_secondary_offline, 0); - spin_lock_init(&port->sep_alua_lock); - mutex_init(&port->sep_tg_pt_md_mutex); + struct se_lun *tmp; spin_lock(&dev->se_port_lock); - if (dev->dev_port_count == 0x0000ffff) { + if (dev->export_count == 0x0000ffff) { pr_warn("Reached dev->dev_port_count ==" " 0x0000ffff\n"); spin_unlock(&dev->se_port_lock); - return ERR_PTR(-ENOSPC); + return -ENOSPC; } again: /* @@ -493,135 +480,23 @@ again: * 2h Relative port 2, historically known as port B * 3h to FFFFh Relative port 3 through 65 535 */ - port->sep_rtpi = dev->dev_rpti_counter++; - if (!port->sep_rtpi) + lun->lun_rtpi = dev->dev_rpti_counter++; + if (!lun->lun_rtpi) goto again; - list_for_each_entry(port_tmp, &dev->dev_sep_list, sep_list) { + list_for_each_entry(tmp, &dev->dev_sep_list, lun_dev_link) { /* * Make sure RELATIVE TARGET PORT IDENTIFIER is unique * for 16-bit wrap.. */ - if (port->sep_rtpi == port_tmp->sep_rtpi) + if (lun->lun_rtpi == tmp->lun_rtpi) goto again; } spin_unlock(&dev->se_port_lock); - return port; -} - -static void core_export_port( - struct se_device *dev, - struct se_portal_group *tpg, - struct se_port *port, - struct se_lun *lun) -{ - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem = NULL; - - spin_lock(&dev->se_port_lock); - spin_lock(&lun->lun_sep_lock); - port->sep_tpg = tpg; - port->sep_lun = lun; - lun->lun_sep = port; - spin_unlock(&lun->lun_sep_lock); - - list_add_tail(&port->sep_list, &dev->dev_sep_list); - spin_unlock(&dev->se_port_lock); - - if (!(dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH) && - !(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) { - tg_pt_gp_mem = core_alua_allocate_tg_pt_gp_mem(port); - if (IS_ERR(tg_pt_gp_mem) || !tg_pt_gp_mem) { - pr_err("Unable to allocate t10_alua_tg_pt" - "_gp_member_t\n"); - return; - } - spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - __core_alua_attach_tg_pt_gp_mem(tg_pt_gp_mem, - dev->t10_alua.default_tg_pt_gp); - spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - pr_debug("%s/%s: Adding to default ALUA Target Port" - " Group: alua/default_tg_pt_gp\n", - dev->transport->name, tpg->se_tpg_tfo->get_fabric_name()); - } - - dev->dev_port_count++; - port->sep_index = port->sep_rtpi; /* RELATIVE TARGET PORT IDENTIFIER */ -} - -/* - * Called with struct se_device->se_port_lock spinlock held. - */ -static void core_release_port(struct se_device *dev, struct se_port *port) - __releases(&dev->se_port_lock) __acquires(&dev->se_port_lock) -{ - /* - * Wait for any port reference for PR ALL_TG_PT=1 operation - * to complete in __core_scsi3_alloc_registration() - */ - spin_unlock(&dev->se_port_lock); - if (atomic_read(&port->sep_tg_pt_ref_cnt)) - cpu_relax(); - spin_lock(&dev->se_port_lock); - - core_alua_free_tg_pt_gp_mem(port); - - list_del(&port->sep_list); - dev->dev_port_count--; - kfree(port); -} - -int core_dev_export( - struct se_device *dev, - struct se_portal_group *tpg, - struct se_lun *lun) -{ - struct se_hba *hba = dev->se_hba; - struct se_port *port; - - port = core_alloc_port(dev); - if (IS_ERR(port)) - return PTR_ERR(port); - - lun->lun_index = dev->dev_index; - lun->lun_se_dev = dev; - lun->lun_rtpi = port->sep_rtpi; - - spin_lock(&hba->device_lock); - dev->export_count++; - spin_unlock(&hba->device_lock); - - core_export_port(dev, tpg, port, lun); return 0; } -void core_dev_unexport( - struct se_device *dev, - struct se_portal_group *tpg, - struct se_lun *lun) -{ - struct se_hba *hba = dev->se_hba; - struct se_port *port = lun->lun_sep; - - spin_lock(&lun->lun_sep_lock); - if (lun->lun_se_dev == NULL) { - spin_unlock(&lun->lun_sep_lock); - return; - } - spin_unlock(&lun->lun_sep_lock); - - spin_lock(&dev->se_port_lock); - core_release_port(dev, port); - spin_unlock(&dev->se_port_lock); - - spin_lock(&hba->device_lock); - dev->export_count--; - spin_unlock(&hba->device_lock); - - lun->lun_sep = NULL; - lun->lun_se_dev = NULL; -} - static void se_release_vpd_for_dev(struct se_device *dev) { struct t10_vpd *vpd, *vpd_tmp; @@ -783,10 +658,10 @@ int core_dev_add_initiator_node_lun_acl( } int core_dev_del_initiator_node_lun_acl( - struct se_portal_group *tpg, struct se_lun *lun, struct se_lun_acl *lacl) { + struct se_portal_group *tpg = lun->lun_tpg; struct se_node_acl *nacl; struct se_dev_entry *deve; @@ -930,6 +805,10 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name) xcopy_lun->lun_se_dev = dev; spin_lock_init(&xcopy_lun->lun_sep_lock); init_completion(&xcopy_lun->lun_ref_comp); + INIT_LIST_HEAD(&xcopy_lun->lun_deve_list); + INIT_LIST_HEAD(&xcopy_lun->lun_dev_link); + mutex_init(&xcopy_lun->lun_tg_pt_md_mutex); + xcopy_lun->lun_tpg = &xcopy_pt_tpg; return dev; } diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index 9be8030e016f..0ee182fce1a6 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -91,12 +91,11 @@ static int target_fabric_mappedlun_link( /* * Ensure that the source port exists */ - if (!lun->lun_sep || !lun->lun_sep->sep_tpg) { - pr_err("Source se_lun->lun_sep or lun->lun_sep->sep" - "_tpg does not exist\n"); + if (!lun->lun_se_dev) { + pr_err("Source se_lun->lun_se_dev does not exist\n"); return -EINVAL; } - se_tpg = lun->lun_sep->sep_tpg; + se_tpg = lun->lun_tpg; nacl_ci = &lun_acl_ci->ci_parent->ci_group->cg_item; tpg_ci = &nacl_ci->ci_group->cg_item; @@ -150,9 +149,8 @@ static int target_fabric_mappedlun_unlink( struct se_lun_acl, se_lun_group); struct se_lun *lun = container_of(to_config_group(lun_ci), struct se_lun, lun_group); - struct se_portal_group *se_tpg = lun->lun_sep->sep_tpg; - return core_dev_del_initiator_node_lun_acl(se_tpg, lun, lacl); + return core_dev_del_initiator_node_lun_acl(lun, lacl); } CONFIGFS_EATTR_STRUCT(target_fabric_mappedlun, se_lun_acl); @@ -643,10 +641,10 @@ static ssize_t target_fabric_port_show_attr_alua_tg_pt_gp( struct se_lun *lun, char *page) { - if (!lun || !lun->lun_sep) + if (!lun || !lun->lun_se_dev) return -ENODEV; - return core_alua_show_tg_pt_gp_info(lun->lun_sep, page); + return core_alua_show_tg_pt_gp_info(lun, page); } static ssize_t target_fabric_port_store_attr_alua_tg_pt_gp( @@ -654,10 +652,10 @@ static ssize_t target_fabric_port_store_attr_alua_tg_pt_gp( const char *page, size_t count) { - if (!lun || !lun->lun_sep) + if (!lun || !lun->lun_se_dev) return -ENODEV; - return core_alua_store_tg_pt_gp_info(lun->lun_sep, page, count); + return core_alua_store_tg_pt_gp_info(lun, page, count); } TCM_PORT_ATTR(alua_tg_pt_gp, S_IRUGO | S_IWUSR); @@ -669,7 +667,7 @@ static ssize_t target_fabric_port_show_attr_alua_tg_pt_offline( struct se_lun *lun, char *page) { - if (!lun || !lun->lun_sep) + if (!lun || !lun->lun_se_dev) return -ENODEV; return core_alua_show_offline_bit(lun, page); @@ -680,7 +678,7 @@ static ssize_t target_fabric_port_store_attr_alua_tg_pt_offline( const char *page, size_t count) { - if (!lun || !lun->lun_sep) + if (!lun || !lun->lun_se_dev) return -ENODEV; return core_alua_store_offline_bit(lun, page, count); @@ -695,7 +693,7 @@ static ssize_t target_fabric_port_show_attr_alua_tg_pt_status( struct se_lun *lun, char *page) { - if (!lun || !lun->lun_sep) + if (!lun || !lun->lun_se_dev) return -ENODEV; return core_alua_show_secondary_status(lun, page); @@ -706,7 +704,7 @@ static ssize_t target_fabric_port_store_attr_alua_tg_pt_status( const char *page, size_t count) { - if (!lun || !lun->lun_sep) + if (!lun || !lun->lun_se_dev) return -ENODEV; return core_alua_store_secondary_status(lun, page, count); @@ -721,7 +719,7 @@ static ssize_t target_fabric_port_show_attr_alua_tg_pt_write_md( struct se_lun *lun, char *page) { - if (!lun || !lun->lun_sep) + if (!lun || !lun->lun_se_dev) return -ENODEV; return core_alua_show_secondary_write_metadata(lun, page); @@ -732,7 +730,7 @@ static ssize_t target_fabric_port_store_attr_alua_tg_pt_write_md( const char *page, size_t count) { - if (!lun || !lun->lun_sep) + if (!lun || !lun->lun_se_dev) return -ENODEV; return core_alua_store_secondary_write_metadata(lun, page, count); @@ -811,7 +809,7 @@ static int target_fabric_port_unlink( { struct se_lun *lun = container_of(to_config_group(lun_ci), struct se_lun, lun_group); - struct se_portal_group *se_tpg = lun->lun_sep->sep_tpg; + struct se_portal_group *se_tpg = lun->lun_tpg; struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; if (tf->tf_ops->fabric_pre_unlink) { diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index 23f992ed7cae..8d8737a13e6f 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -21,6 +21,7 @@ extern struct t10_alua_lu_gp *default_lu_gp; extern struct mutex g_device_mutex; extern struct list_head g_device_list; +int core_alloc_rtpi(struct se_lun *lun, struct se_device *dev); struct se_dev_entry *core_get_se_deve_from_rtpi(struct se_node_acl *, u16); void target_pr_kref_release(struct kref *); void core_free_device_list_for_node(struct se_node_acl *, @@ -32,10 +33,6 @@ int core_enable_device_list_for_node(struct se_lun *, struct se_lun_acl *, void core_disable_device_list_for_node(struct se_lun *, struct se_dev_entry *, struct se_node_acl *, struct se_portal_group *); void core_clear_lun_from_tpg(struct se_lun *, struct se_portal_group *); -int core_dev_export(struct se_device *, struct se_portal_group *, - struct se_lun *); -void core_dev_unexport(struct se_device *, struct se_portal_group *, - struct se_lun *); int core_dev_add_lun(struct se_portal_group *, struct se_device *, struct se_lun *lun); void core_dev_del_lun(struct se_portal_group *, struct se_lun *); @@ -43,8 +40,8 @@ struct se_lun_acl *core_dev_init_initiator_node_lun_acl(struct se_portal_group * struct se_node_acl *, u32, int *); int core_dev_add_initiator_node_lun_acl(struct se_portal_group *, struct se_lun_acl *, struct se_lun *lun, u32); -int core_dev_del_initiator_node_lun_acl(struct se_portal_group *, - struct se_lun *, struct se_lun_acl *); +int core_dev_del_initiator_node_lun_acl(struct se_lun *, + struct se_lun_acl *); void core_dev_free_initiator_node_lun_acl(struct se_portal_group *, struct se_lun_acl *lacl); int core_dev_setup_virtual_lun0(void); @@ -120,4 +117,7 @@ void target_stat_setup_dev_default_groups(struct se_device *); void target_stat_setup_port_default_groups(struct se_lun *); void target_stat_setup_mappedlun_default_groups(struct se_lun_acl *); +/* target_core_xcopy.c */ +extern struct se_portal_group xcopy_pt_tpg; + #endif /* TARGET_CORE_INTERNAL_H */ diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index b983f8a54766..60624bb6c598 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -642,7 +642,7 @@ static struct t10_pr_registration *__core_scsi3_do_alloc_registration( pr_reg->pr_reg_deve = deve; pr_reg->pr_res_mapped_lun = mapped_lun; pr_reg->pr_aptpl_target_lun = lun->unpacked_lun; - pr_reg->tg_pt_sep_rtpi = lun->lun_sep->sep_rtpi; + pr_reg->tg_pt_sep_rtpi = lun->lun_rtpi; pr_reg->pr_res_key = sa_res_key; pr_reg->pr_reg_all_tg_pt = all_tg_pt; pr_reg->pr_reg_aptpl = aptpl; @@ -680,8 +680,7 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( struct se_dev_entry *deve_tmp; struct se_node_acl *nacl_tmp; struct se_lun_acl *lacl_tmp; - struct se_lun *lun_tmp; - struct se_port *port, *port_tmp; + struct se_lun *lun_tmp, *next, *dest_lun; const struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo; struct t10_pr_registration *pr_reg, *pr_reg_atp, *pr_reg_tmp, *pr_reg_tmp_safe; int ret; @@ -704,13 +703,12 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( * for ALL_TG_PT=1 */ spin_lock(&dev->se_port_lock); - list_for_each_entry_safe(port, port_tmp, &dev->dev_sep_list, sep_list) { - atomic_inc_mb(&port->sep_tg_pt_ref_cnt); + list_for_each_entry_safe(lun_tmp, next, &dev->dev_sep_list, lun_dev_link) { + atomic_inc_mb(&lun_tmp->lun_active); spin_unlock(&dev->se_port_lock); - spin_lock_bh(&port->sep_alua_lock); - list_for_each_entry(deve_tmp, &port->sep_alua_list, - alua_port_list) { + spin_lock_bh(&lun_tmp->lun_deve_lock); + list_for_each_entry(deve_tmp, &lun_tmp->lun_deve_list, lun_link) { /* * This pointer will be NULL for demo mode MappedLUNs * that have not been make explicit via a ConfigFS @@ -720,7 +718,7 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( continue; lacl_tmp = rcu_dereference_check(deve_tmp->se_lun_acl, - lockdep_is_held(&port->sep_alua_lock)); + lockdep_is_held(&lun_tmp->lun_deve_lock)); nacl_tmp = lacl_tmp->se_lun_nacl; /* * Skip the matching struct se_node_acl that is allocated @@ -742,7 +740,7 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( continue; kref_get(&deve_tmp->pr_kref); - spin_unlock_bh(&port->sep_alua_lock); + spin_unlock_bh(&lun_tmp->lun_deve_lock); /* * Grab a configfs group dependency that is released * for the exception path at label out: below, or upon @@ -753,7 +751,7 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( if (ret < 0) { pr_err("core_scsi3_lunacl_depend" "_item() failed\n"); - atomic_dec_mb(&port->sep_tg_pt_ref_cnt); + atomic_dec_mb(&lun->lun_active); kref_put(&deve_tmp->pr_kref, target_pr_kref_release); goto out; } @@ -764,27 +762,27 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( * the original *pr_reg is processed in * __core_scsi3_add_registration() */ - lun_tmp = rcu_dereference_check(deve_tmp->se_lun, + dest_lun = rcu_dereference_check(deve_tmp->se_lun, atomic_read(&deve_tmp->pr_kref.refcount) != 0); pr_reg_atp = __core_scsi3_do_alloc_registration(dev, - nacl_tmp, lun_tmp, deve_tmp, + nacl_tmp, dest_lun, deve_tmp, deve_tmp->mapped_lun, NULL, sa_res_key, all_tg_pt, aptpl); if (!pr_reg_atp) { - atomic_dec_mb(&port->sep_tg_pt_ref_cnt); + atomic_dec_mb(&lun_tmp->lun_active); core_scsi3_lunacl_undepend_item(deve_tmp); goto out; } list_add_tail(&pr_reg_atp->pr_reg_atp_mem_list, &pr_reg->pr_reg_atp_list); - spin_lock_bh(&port->sep_alua_lock); + spin_lock_bh(&lun_tmp->lun_deve_lock); } - spin_unlock_bh(&port->sep_alua_lock); + spin_unlock_bh(&lun_tmp->lun_deve_lock); spin_lock(&dev->se_port_lock); - atomic_dec_mb(&port->sep_tg_pt_ref_cnt); + atomic_dec_mb(&lun_tmp->lun_active); } spin_unlock(&dev->se_port_lock); @@ -938,7 +936,7 @@ static int __core_scsi3_check_aptpl_registration( (pr_reg->pr_aptpl_target_lun == target_lun)) { pr_reg->pr_reg_nacl = nacl; - pr_reg->tg_pt_sep_rtpi = lun->lun_sep->sep_rtpi; + pr_reg->tg_pt_sep_rtpi = lun->lun_rtpi; list_del(&pr_reg->pr_reg_aptpl_list); spin_unlock(&pr_tmpl->aptpl_reg_lock); @@ -1465,7 +1463,6 @@ core_scsi3_decode_spec_i_port( int aptpl) { struct se_device *dev = cmd->se_dev; - struct se_port *tmp_port; struct se_portal_group *dest_tpg = NULL, *tmp_tpg; struct se_session *se_sess = cmd->se_sess; struct se_node_acl *dest_node_acl = NULL; @@ -1550,16 +1547,14 @@ core_scsi3_decode_spec_i_port( ptr = &buf[28]; while (tpdl > 0) { - struct se_lun *dest_lun; + struct se_lun *dest_lun, *tmp_lun; proto_ident = (ptr[0] & 0x0f); dest_tpg = NULL; spin_lock(&dev->se_port_lock); - list_for_each_entry(tmp_port, &dev->dev_sep_list, sep_list) { - tmp_tpg = tmp_port->sep_tpg; - if (!tmp_tpg) - continue; + list_for_each_entry(tmp_lun, &dev->dev_sep_list, lun_dev_link) { + tmp_tpg = tmp_lun->lun_tpg; /* * Look for the matching proto_ident provided by @@ -1567,7 +1562,7 @@ core_scsi3_decode_spec_i_port( */ if (tmp_tpg->proto_id != proto_ident) continue; - dest_rtpi = tmp_port->sep_rtpi; + dest_rtpi = tmp_lun->lun_rtpi; i_str = target_parse_pr_out_transport_id(tmp_tpg, (const char *)ptr, &tid_len, &iport_ptr); @@ -3119,9 +3114,8 @@ core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key, struct se_session *se_sess = cmd->se_sess; struct se_device *dev = cmd->se_dev; struct se_dev_entry *dest_se_deve = NULL; - struct se_lun *se_lun = cmd->se_lun; + struct se_lun *se_lun = cmd->se_lun, *tmp_lun; struct se_node_acl *pr_res_nacl, *pr_reg_nacl, *dest_node_acl = NULL; - struct se_port *se_port; struct se_portal_group *se_tpg, *dest_se_tpg = NULL; const struct target_core_fabric_ops *dest_tf_ops = NULL, *tf_ops; struct t10_pr_registration *pr_reg, *pr_res_holder, *dest_pr_reg; @@ -3206,12 +3200,10 @@ core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key, } spin_lock(&dev->se_port_lock); - list_for_each_entry(se_port, &dev->dev_sep_list, sep_list) { - if (se_port->sep_rtpi != rtpi) - continue; - dest_se_tpg = se_port->sep_tpg; - if (!dest_se_tpg) + list_for_each_entry(tmp_lun, &dev->dev_sep_list, lun_dev_link) { + if (tmp_lun->lun_rtpi != rtpi) continue; + dest_se_tpg = tmp_lun->lun_tpg; dest_tf_ops = dest_se_tpg->se_tpg_tfo; if (!dest_tf_ops) continue; diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index 9f995b87b8d1..34d8292a4432 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -37,10 +37,9 @@ #include "target_core_ua.h" #include "target_core_xcopy.h" -static void spc_fill_alua_data(struct se_port *port, unsigned char *buf) +static void spc_fill_alua_data(struct se_lun *lun, unsigned char *buf) { struct t10_alua_tg_pt_gp *tg_pt_gp; - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; /* * Set SCCS for MAINTENANCE_IN + REPORT_TARGET_PORT_GROUPS. @@ -53,17 +52,11 @@ static void spc_fill_alua_data(struct se_port *port, unsigned char *buf) * * See spc4r17 section 6.4.2 Table 135 */ - if (!port) - return; - tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; - if (!tg_pt_gp_mem) - return; - - spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; + spin_lock(&lun->lun_tg_pt_gp_lock); + tg_pt_gp = lun->lun_tg_pt_gp; if (tg_pt_gp) buf[5] |= tg_pt_gp->tg_pt_gp_alua_access_type; - spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + spin_unlock(&lun->lun_tg_pt_gp_lock); } sense_reason_t @@ -94,7 +87,7 @@ spc_emulate_inquiry_std(struct se_cmd *cmd, unsigned char *buf) /* * Enable SCCS and TPGS fields for Emulated ALUA */ - spc_fill_alua_data(lun->lun_sep, buf); + spc_fill_alua_data(lun, buf); /* * Set Third-Party Copy (3PC) bit to indicate support for EXTENDED_COPY @@ -181,11 +174,9 @@ spc_emulate_evpd_83(struct se_cmd *cmd, unsigned char *buf) { struct se_device *dev = cmd->se_dev; struct se_lun *lun = cmd->se_lun; - struct se_port *port = NULL; struct se_portal_group *tpg = NULL; struct t10_alua_lu_gp_member *lu_gp_mem; struct t10_alua_tg_pt_gp *tg_pt_gp; - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; unsigned char *prod = &dev->t10_wwn.model[0]; u32 prod_len; u32 unit_serial_len, off = 0; @@ -267,18 +258,15 @@ check_t10_vend_desc: /* Header size for Designation descriptor */ len += (id_len + 4); off += (id_len + 4); - /* - * struct se_port is only set for INQUIRY VPD=1 through $FABRIC_MOD - */ - port = lun->lun_sep; - if (port) { + + if (1) { struct t10_alua_lu_gp *lu_gp; u32 padding, scsi_name_len, scsi_target_len; u16 lu_gp_id = 0; u16 tg_pt_gp_id = 0; u16 tpgt; - tpg = port->sep_tpg; + tpg = lun->lun_tpg; /* * Relative target port identifer, see spc4r17 * section 7.7.3.7 @@ -298,8 +286,8 @@ check_t10_vend_desc: /* Skip over Obsolete field in RTPI payload * in Table 472 */ off += 2; - buf[off++] = ((port->sep_rtpi >> 8) & 0xff); - buf[off++] = (port->sep_rtpi & 0xff); + buf[off++] = ((lun->lun_rtpi >> 8) & 0xff); + buf[off++] = (lun->lun_rtpi & 0xff); len += 8; /* Header size + Designation descriptor */ /* * Target port group identifier, see spc4r17 @@ -308,18 +296,14 @@ check_t10_vend_desc: * Get the PROTOCOL IDENTIFIER as defined by spc4r17 * section 7.5.1 Table 362 */ - tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; - if (!tg_pt_gp_mem) - goto check_lu_gp; - - spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; + spin_lock(&lun->lun_tg_pt_gp_lock); + tg_pt_gp = lun->lun_tg_pt_gp; if (!tg_pt_gp) { - spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + spin_unlock(&lun->lun_tg_pt_gp_lock); goto check_lu_gp; } tg_pt_gp_id = tg_pt_gp->tg_pt_gp_id; - spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + spin_unlock(&lun->lun_tg_pt_gp_lock); buf[off] = tpg->proto_id << 4; buf[off++] |= 0x1; /* CODE SET == Binary */ @@ -694,7 +678,7 @@ static sense_reason_t spc_emulate_inquiry(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; - struct se_portal_group *tpg = cmd->se_lun->lun_sep->sep_tpg; + struct se_portal_group *tpg = cmd->se_lun->lun_tpg; unsigned char *rbuf; unsigned char *cdb = cmd->t_task_cdb; unsigned char *buf; @@ -708,7 +692,7 @@ spc_emulate_inquiry(struct se_cmd *cmd) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } - if (dev == tpg->tpg_virt_lun0.lun_se_dev) + if (dev == tpg->tpg_virt_lun0->lun_se_dev) buf[0] = 0x3f; /* Not connected */ else buf[0] = dev->transport->get_device_type(dev); diff --git a/drivers/target/target_core_stat.c b/drivers/target/target_core_stat.c index ea1287940a7c..8e080efb0188 100644 --- a/drivers/target/target_core_stat.c +++ b/drivers/target/target_core_stat.c @@ -106,7 +106,7 @@ static ssize_t target_stat_scsi_dev_show_attr_ports( struct se_device *dev = container_of(sgrps, struct se_device, dev_stat_grps); - return snprintf(page, PAGE_SIZE, "%u\n", dev->dev_port_count); + return snprintf(page, PAGE_SIZE, "%u\n", dev->export_count); } DEV_STAT_SCSI_DEV_ATTR_RO(ports); @@ -542,19 +542,13 @@ static ssize_t target_stat_scsi_port_show_attr_inst( struct se_port_stat_grps *pgrps, char *page) { struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); - struct se_port *sep; - struct se_device *dev = lun->lun_se_dev; - struct se_hba *hba; - ssize_t ret; + struct se_device *dev; + ssize_t ret = -ENODEV; spin_lock(&lun->lun_sep_lock); - sep = lun->lun_sep; - if (!sep) { - spin_unlock(&lun->lun_sep_lock); - return -ENODEV; - } - hba = dev->se_hba; - ret = snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index); + dev = lun->lun_se_dev; + if (dev) + ret = snprintf(page, PAGE_SIZE, "%u\n", dev->se_hba->hba_index); spin_unlock(&lun->lun_sep_lock); return ret; } @@ -564,17 +558,13 @@ static ssize_t target_stat_scsi_port_show_attr_dev( struct se_port_stat_grps *pgrps, char *page) { struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); - struct se_port *sep; - struct se_device *dev = lun->lun_se_dev; - ssize_t ret; + struct se_device *dev; + ssize_t ret = -ENODEV; spin_lock(&lun->lun_sep_lock); - sep = lun->lun_sep; - if (!sep) { - spin_unlock(&lun->lun_sep_lock); - return -ENODEV; - } - ret = snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index); + dev = lun->lun_se_dev; + if (dev) + ret = snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index); spin_unlock(&lun->lun_sep_lock); return ret; } @@ -584,16 +574,13 @@ static ssize_t target_stat_scsi_port_show_attr_indx( struct se_port_stat_grps *pgrps, char *page) { struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); - struct se_port *sep; - ssize_t ret; + struct se_device *dev; + ssize_t ret = -ENODEV; spin_lock(&lun->lun_sep_lock); - sep = lun->lun_sep; - if (!sep) { - spin_unlock(&lun->lun_sep_lock); - return -ENODEV; - } - ret = snprintf(page, PAGE_SIZE, "%u\n", sep->sep_index); + dev = lun->lun_se_dev; + if (dev) + ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_rtpi); spin_unlock(&lun->lun_sep_lock); return ret; } @@ -603,20 +590,13 @@ static ssize_t target_stat_scsi_port_show_attr_role( struct se_port_stat_grps *pgrps, char *page) { struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); - struct se_device *dev = lun->lun_se_dev; - struct se_port *sep; - ssize_t ret; - - if (!dev) - return -ENODEV; + struct se_device *dev; + ssize_t ret = -ENODEV; spin_lock(&lun->lun_sep_lock); - sep = lun->lun_sep; - if (!sep) { - spin_unlock(&lun->lun_sep_lock); - return -ENODEV; - } - ret = snprintf(page, PAGE_SIZE, "%s%u\n", "Device", dev->dev_index); + dev = lun->lun_se_dev; + if (dev) + ret = snprintf(page, PAGE_SIZE, "%s%u\n", "Device", dev->dev_index); spin_unlock(&lun->lun_sep_lock); return ret; } @@ -626,17 +606,15 @@ static ssize_t target_stat_scsi_port_show_attr_busy_count( struct se_port_stat_grps *pgrps, char *page) { struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); - struct se_port *sep; - ssize_t ret; + struct se_device *dev; + ssize_t ret = -ENODEV; spin_lock(&lun->lun_sep_lock); - sep = lun->lun_sep; - if (!sep) { - spin_unlock(&lun->lun_sep_lock); - return -ENODEV; + dev = lun->lun_se_dev; + if (dev) { + /* FIXME: scsiPortBusyStatuses */ + ret = snprintf(page, PAGE_SIZE, "%u\n", 0); } - /* FIXME: scsiPortBusyStatuses */ - ret = snprintf(page, PAGE_SIZE, "%u\n", 0); spin_unlock(&lun->lun_sep_lock); return ret; } @@ -685,19 +663,13 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_inst( struct se_port_stat_grps *pgrps, char *page) { struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); - struct se_device *dev = lun->lun_se_dev; - struct se_port *sep; - struct se_hba *hba; - ssize_t ret; + struct se_device *dev; + ssize_t ret = -ENODEV; spin_lock(&lun->lun_sep_lock); - sep = lun->lun_sep; - if (!sep) { - spin_unlock(&lun->lun_sep_lock); - return -ENODEV; - } - hba = dev->se_hba; - ret = snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index); + dev = lun->lun_se_dev; + if (dev) + ret = snprintf(page, PAGE_SIZE, "%u\n", dev->se_hba->hba_index); spin_unlock(&lun->lun_sep_lock); return ret; } @@ -707,17 +679,13 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_dev( struct se_port_stat_grps *pgrps, char *page) { struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); - struct se_device *dev = lun->lun_se_dev; - struct se_port *sep; - ssize_t ret; + struct se_device *dev; + ssize_t ret = -ENODEV; spin_lock(&lun->lun_sep_lock); - sep = lun->lun_sep; - if (!sep) { - spin_unlock(&lun->lun_sep_lock); - return -ENODEV; - } - ret = snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index); + dev = lun->lun_se_dev; + if (dev) + ret = snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index); spin_unlock(&lun->lun_sep_lock); return ret; } @@ -727,16 +695,13 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_indx( struct se_port_stat_grps *pgrps, char *page) { struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); - struct se_port *sep; - ssize_t ret; + struct se_device *dev; + ssize_t ret = -ENODEV; spin_lock(&lun->lun_sep_lock); - sep = lun->lun_sep; - if (!sep) { - spin_unlock(&lun->lun_sep_lock); - return -ENODEV; - } - ret = snprintf(page, PAGE_SIZE, "%u\n", sep->sep_index); + dev = lun->lun_se_dev; + if (dev) + ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_rtpi); spin_unlock(&lun->lun_sep_lock); return ret; } @@ -746,20 +711,16 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_name( struct se_port_stat_grps *pgrps, char *page) { struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); - struct se_port *sep; - struct se_portal_group *tpg; - ssize_t ret; + struct se_portal_group *tpg = lun->lun_tpg; + struct se_device *dev; + ssize_t ret = -ENODEV; spin_lock(&lun->lun_sep_lock); - sep = lun->lun_sep; - if (!sep) { - spin_unlock(&lun->lun_sep_lock); - return -ENODEV; - } - tpg = sep->sep_tpg; - - ret = snprintf(page, PAGE_SIZE, "%sPort#%u\n", - tpg->se_tpg_tfo->get_fabric_name(), sep->sep_index); + dev = lun->lun_se_dev; + if (dev) + ret = snprintf(page, PAGE_SIZE, "%sPort#%u\n", + tpg->se_tpg_tfo->get_fabric_name(), + lun->lun_rtpi); spin_unlock(&lun->lun_sep_lock); return ret; } @@ -769,21 +730,16 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_port_index( struct se_port_stat_grps *pgrps, char *page) { struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); - struct se_port *sep; - struct se_portal_group *tpg; - ssize_t ret; + struct se_portal_group *tpg = lun->lun_tpg; + struct se_device *dev; + ssize_t ret = -ENODEV; spin_lock(&lun->lun_sep_lock); - sep = lun->lun_sep; - if (!sep) { - spin_unlock(&lun->lun_sep_lock); - return -ENODEV; - } - tpg = sep->sep_tpg; - - ret = snprintf(page, PAGE_SIZE, "%s%s%d\n", - tpg->se_tpg_tfo->tpg_get_wwn(tpg), "+t+", - tpg->se_tpg_tfo->tpg_get_tag(tpg)); + dev = lun->lun_se_dev; + if (dev) + ret = snprintf(page, PAGE_SIZE, "%s%s%d\n", + tpg->se_tpg_tfo->tpg_get_wwn(tpg), "+t+", + tpg->se_tpg_tfo->tpg_get_tag(tpg)); spin_unlock(&lun->lun_sep_lock); return ret; } @@ -793,17 +749,13 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_in_cmds( struct se_port_stat_grps *pgrps, char *page) { struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); - struct se_port *sep; - ssize_t ret; + struct se_device *dev; + ssize_t ret = -ENODEV; spin_lock(&lun->lun_sep_lock); - sep = lun->lun_sep; - if (!sep) { - spin_unlock(&lun->lun_sep_lock); - return -ENODEV; - } - - ret = snprintf(page, PAGE_SIZE, "%llu\n", sep->sep_stats.cmd_pdus); + dev = lun->lun_se_dev; + if (dev) + ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_stats.cmd_pdus); spin_unlock(&lun->lun_sep_lock); return ret; } @@ -813,18 +765,14 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_write_mbytes( struct se_port_stat_grps *pgrps, char *page) { struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); - struct se_port *sep; - ssize_t ret; + struct se_device *dev; + ssize_t ret = -ENODEV; spin_lock(&lun->lun_sep_lock); - sep = lun->lun_sep; - if (!sep) { - spin_unlock(&lun->lun_sep_lock); - return -ENODEV; - } - - ret = snprintf(page, PAGE_SIZE, "%u\n", - (u32)(sep->sep_stats.rx_data_octets >> 20)); + dev = lun->lun_se_dev; + if (dev) + ret = snprintf(page, PAGE_SIZE, "%u\n", + (u32)(lun->lun_stats.rx_data_octets >> 20)); spin_unlock(&lun->lun_sep_lock); return ret; } @@ -834,18 +782,14 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_read_mbytes( struct se_port_stat_grps *pgrps, char *page) { struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); - struct se_port *sep; - ssize_t ret; + struct se_device *dev; + ssize_t ret = -ENODEV; spin_lock(&lun->lun_sep_lock); - sep = lun->lun_sep; - if (!sep) { - spin_unlock(&lun->lun_sep_lock); - return -ENODEV; - } - - ret = snprintf(page, PAGE_SIZE, "%u\n", - (u32)(sep->sep_stats.tx_data_octets >> 20)); + dev = lun->lun_se_dev; + if (dev) + ret = snprintf(page, PAGE_SIZE, "%u\n", + (u32)(lun->lun_stats.tx_data_octets >> 20)); spin_unlock(&lun->lun_sep_lock); return ret; } @@ -855,18 +799,15 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_hs_in_cmds( struct se_port_stat_grps *pgrps, char *page) { struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); - struct se_port *sep; - ssize_t ret; + struct se_device *dev; + ssize_t ret = -ENODEV; spin_lock(&lun->lun_sep_lock); - sep = lun->lun_sep; - if (!sep) { - spin_unlock(&lun->lun_sep_lock); - return -ENODEV; + dev = lun->lun_se_dev; + if (dev) { + /* FIXME: scsiTgtPortHsInCommands */ + ret = snprintf(page, PAGE_SIZE, "%u\n", 0); } - - /* FIXME: scsiTgtPortHsInCommands */ - ret = snprintf(page, PAGE_SIZE, "%u\n", 0); spin_unlock(&lun->lun_sep_lock); return ret; } @@ -921,20 +862,13 @@ static ssize_t target_stat_scsi_transport_show_attr_inst( struct se_port_stat_grps *pgrps, char *page) { struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); - struct se_device *dev = lun->lun_se_dev; - struct se_port *sep; - struct se_hba *hba; - ssize_t ret; + struct se_device *dev; + ssize_t ret = -ENODEV; spin_lock(&lun->lun_sep_lock); - sep = lun->lun_sep; - if (!sep) { - spin_unlock(&lun->lun_sep_lock); - return -ENODEV; - } - - hba = dev->se_hba; - ret = snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index); + dev = lun->lun_se_dev; + if (dev) + ret = snprintf(page, PAGE_SIZE, "%u\n", dev->se_hba->hba_index); spin_unlock(&lun->lun_sep_lock); return ret; } @@ -944,20 +878,17 @@ static ssize_t target_stat_scsi_transport_show_attr_device( struct se_port_stat_grps *pgrps, char *page) { struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); - struct se_port *sep; - struct se_portal_group *tpg; - ssize_t ret; + struct se_device *dev; + struct se_portal_group *tpg = lun->lun_tpg; + ssize_t ret = -ENODEV; spin_lock(&lun->lun_sep_lock); - sep = lun->lun_sep; - if (!sep) { - spin_unlock(&lun->lun_sep_lock); - return -ENODEV; + dev = lun->lun_se_dev; + if (dev) { + /* scsiTransportType */ + ret = snprintf(page, PAGE_SIZE, "scsiTransport%s\n", + tpg->se_tpg_tfo->get_fabric_name()); } - tpg = sep->sep_tpg; - /* scsiTransportType */ - ret = snprintf(page, PAGE_SIZE, "scsiTransport%s\n", - tpg->se_tpg_tfo->get_fabric_name()); spin_unlock(&lun->lun_sep_lock); return ret; } @@ -967,19 +898,15 @@ static ssize_t target_stat_scsi_transport_show_attr_indx( struct se_port_stat_grps *pgrps, char *page) { struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); - struct se_port *sep; - struct se_portal_group *tpg; - ssize_t ret; + struct se_device *dev; + struct se_portal_group *tpg = lun->lun_tpg; + ssize_t ret = -ENODEV; spin_lock(&lun->lun_sep_lock); - sep = lun->lun_sep; - if (!sep) { - spin_unlock(&lun->lun_sep_lock); - return -ENODEV; - } - tpg = sep->sep_tpg; - ret = snprintf(page, PAGE_SIZE, "%u\n", - tpg->se_tpg_tfo->tpg_get_inst_index(tpg)); + dev = lun->lun_se_dev; + if (dev) + ret = snprintf(page, PAGE_SIZE, "%u\n", + tpg->se_tpg_tfo->tpg_get_inst_index(tpg)); spin_unlock(&lun->lun_sep_lock); return ret; } @@ -990,24 +917,20 @@ static ssize_t target_stat_scsi_transport_show_attr_dev_name( { struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); struct se_device *dev = lun->lun_se_dev; - struct se_port *sep; - struct se_portal_group *tpg; + struct se_portal_group *tpg = lun->lun_tpg; struct t10_wwn *wwn; - ssize_t ret; + ssize_t ret = -ENODEV; spin_lock(&lun->lun_sep_lock); - sep = lun->lun_sep; - if (!sep) { - spin_unlock(&lun->lun_sep_lock); - return -ENODEV; + dev = lun->lun_se_dev; + if (dev) { + wwn = &dev->t10_wwn; + /* scsiTransportDevName */ + ret = snprintf(page, PAGE_SIZE, "%s+%s\n", + tpg->se_tpg_tfo->tpg_get_wwn(tpg), + (strlen(wwn->unit_serial)) ? wwn->unit_serial : + wwn->vendor); } - tpg = sep->sep_tpg; - wwn = &dev->t10_wwn; - /* scsiTransportDevName */ - ret = snprintf(page, PAGE_SIZE, "%s+%s\n", - tpg->se_tpg_tfo->tpg_get_wwn(tpg), - (strlen(wwn->unit_serial)) ? wwn->unit_serial : - wwn->vendor); spin_unlock(&lun->lun_sep_lock); return ret; } diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index fd531fcf3191..499b1399035a 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -40,6 +40,7 @@ #include #include "target_core_internal.h" +#include "target_core_alua.h" #include "target_core_pr.h" extern struct se_device *g_lun0_dev; @@ -484,32 +485,14 @@ static void core_tpg_lun_ref_release(struct percpu_ref *ref) complete(&lun->lun_ref_comp); } -static int core_tpg_setup_virtual_lun0(struct se_portal_group *se_tpg) -{ - /* Set in core_dev_setup_virtual_lun0() */ - struct se_device *dev = g_lun0_dev; - struct se_lun *lun = &se_tpg->tpg_virt_lun0; - u32 lun_access = TRANSPORT_LUNFLAGS_READ_ONLY; - int ret; - - lun->unpacked_lun = 0; - atomic_set(&lun->lun_acl_count, 0); - spin_lock_init(&lun->lun_sep_lock); - init_completion(&lun->lun_ref_comp); - - ret = core_tpg_add_lun(se_tpg, lun, lun_access, dev); - if (ret < 0) - return ret; - - return 0; -} - int core_tpg_register( const struct target_core_fabric_ops *tfo, struct se_wwn *se_wwn, struct se_portal_group *se_tpg, int proto_id) { + int ret; + INIT_HLIST_HEAD(&se_tpg->tpg_lun_hlist); se_tpg->proto_id = proto_id; se_tpg->se_tpg_tfo = tfo; @@ -523,8 +506,16 @@ int core_tpg_register( mutex_init(&se_tpg->acl_node_mutex); if (se_tpg->proto_id >= 0) { - if (core_tpg_setup_virtual_lun0(se_tpg) < 0) - return -ENOMEM; + se_tpg->tpg_virt_lun0 = core_tpg_alloc_lun(se_tpg, 0); + if (IS_ERR(se_tpg->tpg_virt_lun0)) + return PTR_ERR(se_tpg->tpg_virt_lun0); + + ret = core_tpg_add_lun(se_tpg, se_tpg->tpg_virt_lun0, + TRANSPORT_LUNFLAGS_READ_ONLY, g_lun0_dev); + if (ret < 0) { + kfree(se_tpg->tpg_virt_lun0); + return ret; + } } spin_lock_bh(&tpg_lock); @@ -575,8 +566,10 @@ int core_tpg_deregister(struct se_portal_group *se_tpg) kfree(nacl); } - if (se_tpg->proto_id >= 0) - core_tpg_remove_lun(se_tpg, &se_tpg->tpg_virt_lun0); + if (se_tpg->proto_id >= 0) { + core_tpg_remove_lun(se_tpg, se_tpg->tpg_virt_lun0); + kfree_rcu(se_tpg->tpg_virt_lun0, rcu_head); + } return 0; } @@ -607,6 +600,15 @@ struct se_lun *core_tpg_alloc_lun( atomic_set(&lun->lun_acl_count, 0); spin_lock_init(&lun->lun_sep_lock); init_completion(&lun->lun_ref_comp); + INIT_LIST_HEAD(&lun->lun_deve_list); + INIT_LIST_HEAD(&lun->lun_dev_link); + atomic_set(&lun->lun_tg_pt_secondary_offline, 0); + spin_lock_init(&lun->lun_deve_lock); + mutex_init(&lun->lun_tg_pt_md_mutex); + INIT_LIST_HEAD(&lun->lun_tg_pt_gp_link); + spin_lock_init(&lun->lun_tg_pt_gp_lock); + atomic_set(&lun->lun_active, 0); + lun->lun_tpg = tpg; return lun; } @@ -622,21 +624,40 @@ int core_tpg_add_lun( ret = percpu_ref_init(&lun->lun_ref, core_tpg_lun_ref_release, 0, GFP_KERNEL); if (ret < 0) - return ret; + goto out; - ret = core_dev_export(dev, tpg, lun); - if (ret < 0) { - percpu_ref_exit(&lun->lun_ref); - return ret; - } + ret = core_alloc_rtpi(lun, dev); + if (ret) + goto out_kill_ref; + + if (!(dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH) && + !(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) + target_attach_tg_pt_gp(lun, dev->t10_alua.default_tg_pt_gp); mutex_lock(&tpg->tpg_lun_mutex); + + spin_lock(&lun->lun_sep_lock); + lun->lun_index = dev->dev_index; + lun->lun_se_dev = dev; + spin_unlock(&lun->lun_sep_lock); + + spin_lock(&dev->se_port_lock); + rcu_assign_pointer(lun->lun_se_dev, dev); + dev->export_count++; + list_add_tail(&lun->lun_dev_link, &dev->dev_sep_list); + spin_unlock(&dev->se_port_lock); + lun->lun_access = lun_access; if (!(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) hlist_add_head_rcu(&lun->link, &tpg->tpg_lun_hlist); mutex_unlock(&tpg->tpg_lun_mutex); return 0; + +out_kill_ref: + percpu_ref_exit(&lun->lun_ref); +out: + return ret; } void core_tpg_remove_lun( @@ -648,9 +669,19 @@ void core_tpg_remove_lun( core_clear_lun_from_tpg(lun, tpg); transport_clear_lun_ref(lun); - core_dev_unexport(lun->lun_se_dev, tpg, lun); - mutex_lock(&tpg->tpg_lun_mutex); + if (lun->lun_se_dev) { + while (atomic_read(&lun->lun_active)) + cpu_relax(); + + target_detach_tg_pt_gp(lun); + + spin_lock(&dev->se_port_lock); + list_del(&lun->lun_dev_link); + dev->export_count--; + rcu_assign_pointer(lun->lun_se_dev, NULL); + spin_unlock(&dev->se_port_lock); + } if (!(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) hlist_del_rcu(&lun->link); mutex_unlock(&tpg->tpg_lun_mutex); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 7c0518a28186..ef6fdd8a47c4 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -60,7 +60,6 @@ struct kmem_cache *t10_pr_reg_cache; struct kmem_cache *t10_alua_lu_gp_cache; struct kmem_cache *t10_alua_lu_gp_mem_cache; struct kmem_cache *t10_alua_tg_pt_gp_cache; -struct kmem_cache *t10_alua_tg_pt_gp_mem_cache; struct kmem_cache *t10_alua_lba_map_cache; struct kmem_cache *t10_alua_lba_map_mem_cache; @@ -119,16 +118,6 @@ int init_se_kmem_caches(void) "cache failed\n"); goto out_free_lu_gp_mem_cache; } - t10_alua_tg_pt_gp_mem_cache = kmem_cache_create( - "t10_alua_tg_pt_gp_mem_cache", - sizeof(struct t10_alua_tg_pt_gp_member), - __alignof__(struct t10_alua_tg_pt_gp_member), - 0, NULL); - if (!t10_alua_tg_pt_gp_mem_cache) { - pr_err("kmem_cache_create() for t10_alua_tg_pt_gp_" - "mem_t failed\n"); - goto out_free_tg_pt_gp_cache; - } t10_alua_lba_map_cache = kmem_cache_create( "t10_alua_lba_map_cache", sizeof(struct t10_alua_lba_map), @@ -136,7 +125,7 @@ int init_se_kmem_caches(void) if (!t10_alua_lba_map_cache) { pr_err("kmem_cache_create() for t10_alua_lba_map_" "cache failed\n"); - goto out_free_tg_pt_gp_mem_cache; + goto out_free_tg_pt_gp_cache; } t10_alua_lba_map_mem_cache = kmem_cache_create( "t10_alua_lba_map_mem_cache", @@ -159,8 +148,6 @@ out_free_lba_map_mem_cache: kmem_cache_destroy(t10_alua_lba_map_mem_cache); out_free_lba_map_cache: kmem_cache_destroy(t10_alua_lba_map_cache); -out_free_tg_pt_gp_mem_cache: - kmem_cache_destroy(t10_alua_tg_pt_gp_mem_cache); out_free_tg_pt_gp_cache: kmem_cache_destroy(t10_alua_tg_pt_gp_cache); out_free_lu_gp_mem_cache: @@ -186,7 +173,6 @@ void release_se_kmem_caches(void) kmem_cache_destroy(t10_alua_lu_gp_cache); kmem_cache_destroy(t10_alua_lu_gp_mem_cache); kmem_cache_destroy(t10_alua_tg_pt_gp_cache); - kmem_cache_destroy(t10_alua_tg_pt_gp_mem_cache); kmem_cache_destroy(t10_alua_lba_map_cache); kmem_cache_destroy(t10_alua_lba_map_mem_cache); } @@ -1277,8 +1263,7 @@ target_setup_cmd_from_cdb(struct se_cmd *cmd, unsigned char *cdb) cmd->se_cmd_flags |= SCF_SUPPORTED_SAM_OPCODE; spin_lock(&cmd->se_lun->lun_sep_lock); - if (cmd->se_lun->lun_sep) - cmd->se_lun->lun_sep->sep_stats.cmd_pdus++; + cmd->se_lun->lun_stats.cmd_pdus++; spin_unlock(&cmd->se_lun->lun_sep_lock); return 0; } @@ -2076,10 +2061,7 @@ queue_rsp: switch (cmd->data_direction) { case DMA_FROM_DEVICE: spin_lock(&cmd->se_lun->lun_sep_lock); - if (cmd->se_lun->lun_sep) { - cmd->se_lun->lun_sep->sep_stats.tx_data_octets += - cmd->data_length; - } + cmd->se_lun->lun_stats.tx_data_octets += cmd->data_length; spin_unlock(&cmd->se_lun->lun_sep_lock); /* * Perform READ_STRIP of PI using software emulation when @@ -2104,20 +2086,14 @@ queue_rsp: break; case DMA_TO_DEVICE: spin_lock(&cmd->se_lun->lun_sep_lock); - if (cmd->se_lun->lun_sep) { - cmd->se_lun->lun_sep->sep_stats.rx_data_octets += - cmd->data_length; - } + cmd->se_lun->lun_stats.rx_data_octets += cmd->data_length; spin_unlock(&cmd->se_lun->lun_sep_lock); /* * Check if we need to send READ payload for BIDI-COMMAND */ if (cmd->se_cmd_flags & SCF_BIDI) { spin_lock(&cmd->se_lun->lun_sep_lock); - if (cmd->se_lun->lun_sep) { - cmd->se_lun->lun_sep->sep_stats.tx_data_octets += - cmd->data_length; - } + cmd->se_lun->lun_stats.tx_data_octets += cmd->data_length; spin_unlock(&cmd->se_lun->lun_sep_lock); ret = cmd->se_tfo->queue_data_in(cmd); if (ret == -EAGAIN || ret == -ENOMEM) diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c index 3556a9dcee46..49111d39e795 100644 --- a/drivers/target/target_core_xcopy.c +++ b/drivers/target/target_core_xcopy.c @@ -348,8 +348,7 @@ struct xcopy_pt_cmd { unsigned char sense_buffer[TRANSPORT_SENSE_BUFFER]; }; -static struct se_port xcopy_pt_port; -static struct se_portal_group xcopy_pt_tpg; +struct se_portal_group xcopy_pt_tpg; static struct se_session xcopy_pt_sess; static struct se_node_acl xcopy_pt_nacl; @@ -439,17 +438,11 @@ int target_xcopy_setup_pt(void) return -ENOMEM; } - memset(&xcopy_pt_port, 0, sizeof(struct se_port)); - INIT_LIST_HEAD(&xcopy_pt_port.sep_alua_list); - INIT_LIST_HEAD(&xcopy_pt_port.sep_list); - mutex_init(&xcopy_pt_port.sep_tg_pt_md_mutex); - memset(&xcopy_pt_tpg, 0, sizeof(struct se_portal_group)); INIT_LIST_HEAD(&xcopy_pt_tpg.se_tpg_node); INIT_LIST_HEAD(&xcopy_pt_tpg.acl_node_list); INIT_LIST_HEAD(&xcopy_pt_tpg.tpg_sess_list); - xcopy_pt_port.sep_tpg = &xcopy_pt_tpg; xcopy_pt_tpg.se_tpg_tfo = &xcopy_pt_tfo; memset(&xcopy_pt_nacl, 0, sizeof(struct se_node_acl)); @@ -490,10 +483,6 @@ static void target_xcopy_setup_pt_port( */ if (remote_port) { xpt_cmd->remote_port = remote_port; - pt_cmd->se_lun->lun_sep = &xcopy_pt_port; - pr_debug("Setup emulated remote DEST xcopy_pt_port: %p to" - " cmd->se_lun->lun_sep for X-COPY data PUSH\n", - pt_cmd->se_lun->lun_sep); } else { pt_cmd->se_lun = ec_cmd->se_lun; pt_cmd->se_dev = ec_cmd->se_dev; @@ -513,10 +502,6 @@ static void target_xcopy_setup_pt_port( */ if (remote_port) { xpt_cmd->remote_port = remote_port; - pt_cmd->se_lun->lun_sep = &xcopy_pt_port; - pr_debug("Setup emulated remote SRC xcopy_pt_port: %p to" - " cmd->se_lun->lun_sep for X-COPY data PULL\n", - pt_cmd->se_lun->lun_sep); } else { pt_cmd->se_lun = ec_cmd->se_lun; pt_cmd->se_dev = ec_cmd->se_dev; diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index ee7abdd6b7a2..1927dd5947a7 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -304,22 +304,13 @@ struct t10_alua_tg_pt_gp { struct se_device *tg_pt_gp_dev; struct config_group tg_pt_gp_group; struct list_head tg_pt_gp_list; - struct list_head tg_pt_gp_mem_list; - struct se_port *tg_pt_gp_alua_port; + struct list_head tg_pt_gp_lun_list; + struct se_lun *tg_pt_gp_alua_lun; struct se_node_acl *tg_pt_gp_alua_nacl; struct delayed_work tg_pt_gp_transition_work; struct completion *tg_pt_gp_transition_complete; }; -struct t10_alua_tg_pt_gp_member { - bool tg_pt_gp_assoc; - atomic_t tg_pt_gp_mem_ref_cnt; - spinlock_t tg_pt_gp_mem_lock; - struct t10_alua_tg_pt_gp *tg_pt_gp; - struct se_port *tg_pt; - struct list_head tg_pt_gp_mem_list; -}; - struct t10_vpd { unsigned char device_identifier[INQUIRY_VPD_DEVICE_IDENTIFIER_LEN]; int protocol_identifier_set; @@ -650,6 +641,7 @@ struct se_dev_entry { #define DEF_PR_REG_ACTIVE 1 unsigned long deve_flags; struct list_head alua_port_list; + struct list_head lun_link; struct list_head ua_list; struct hlist_node link; struct rcu_head rcu_head; @@ -697,7 +689,14 @@ struct se_port_stat_grps { struct config_group scsi_transport_group; }; +struct scsi_port_stats { + u32 cmd_pdus; + u64 tx_data_octets; + u64 rx_data_octets; +}; + struct se_lun { + /* RELATIVE TARGET PORT IDENTIFER */ u16 lun_rtpi; #define SE_LUN_LINK_MAGIC 0xffff7771 u32 lun_link_magic; @@ -707,12 +706,30 @@ struct se_lun { u32 lun_index; atomic_t lun_acl_count; spinlock_t lun_sep_lock; - struct se_device *lun_se_dev; - struct se_port *lun_sep; + struct se_device __rcu *lun_se_dev; + + struct list_head lun_deve_list; + spinlock_t lun_deve_lock; + + /* ALUA state */ + int lun_tg_pt_secondary_stat; + int lun_tg_pt_secondary_write_md; + atomic_t lun_tg_pt_secondary_offline; + struct mutex lun_tg_pt_md_mutex; + + /* ALUA target port group linkage */ + struct list_head lun_tg_pt_gp_link; + struct t10_alua_tg_pt_gp *lun_tg_pt_gp; + spinlock_t lun_tg_pt_gp_lock; + + atomic_t lun_active; + struct se_portal_group *lun_tpg; + struct scsi_port_stats lun_stats; struct config_group lun_group; struct se_port_stat_grps port_stat_grps; struct completion lun_ref_comp; struct percpu_ref lun_ref; + struct list_head lun_dev_link; struct hlist_node link; struct rcu_head rcu_head; }; @@ -737,7 +754,6 @@ struct se_device { #define DF_EMULATED_VPD_UNIT_SERIAL 0x00000004 #define DF_USING_UDEV_PATH 0x00000008 #define DF_USING_ALIAS 0x00000010 - u32 dev_port_count; /* Physical device queue depth */ u32 queue_depth; /* Used for SPC-2 reservations enforce of ISIDs */ @@ -754,7 +770,7 @@ struct se_device { atomic_t dev_ordered_id; atomic_t dev_ordered_sync; atomic_t dev_qf_count; - int export_count; + u32 export_count; spinlock_t delayed_cmd_lock; spinlock_t execute_task_lock; spinlock_t dev_reservation_lock; @@ -821,32 +837,6 @@ struct se_hba { struct target_backend *backend; }; -struct scsi_port_stats { - u64 cmd_pdus; - u64 tx_data_octets; - u64 rx_data_octets; -}; - -struct se_port { - /* RELATIVE TARGET PORT IDENTIFER */ - u16 sep_rtpi; - int sep_tg_pt_secondary_stat; - int sep_tg_pt_secondary_write_md; - u32 sep_index; - struct scsi_port_stats sep_stats; - /* Used for ALUA Target Port Groups membership */ - atomic_t sep_tg_pt_secondary_offline; - /* Used for PR ALL_TG_PT=1 */ - atomic_t sep_tg_pt_ref_cnt; - spinlock_t sep_alua_lock; - struct mutex sep_tg_pt_md_mutex; - struct t10_alua_tg_pt_gp_member *sep_alua_tg_pt_gp_mem; - struct se_lun *sep_lun; - struct se_portal_group *sep_tpg; - struct list_head sep_alua_list; - struct list_head sep_list; -}; - struct se_tpg_np { struct se_portal_group *tpg_np_parent; struct config_group tpg_np_group; @@ -872,7 +862,7 @@ struct se_portal_group { /* linked list for initiator ACL list */ struct list_head acl_node_list; struct hlist_head tpg_lun_hlist; - struct se_lun tpg_virt_lun0; + struct se_lun *tpg_virt_lun0; /* List of TCM sessions associated wth this TPG */ struct list_head tpg_sess_list; /* Pointer to $FABRIC_MOD dependent code */ -- cgit v1.2.3-70-g09d2 From 4cc987eaff9144182cde88d6d132420c28d3f81b Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Tue, 19 May 2015 00:03:07 -0700 Subject: target: Drop lun_sep_lock for se_lun->lun_se_dev RCU usage With se_port and t10_alua_tg_pt_gp_member being absored into se_lun, there is no need for an extra lock to protect se_lun->lun_se_dev assignment. This patch also converts backend drivers to use call_rcu() release to allow any se_device readers to complete. The call_rcu() instead of kfree_rcu() is required here because se_device is embedded into the backend driver specific structure. Also, convert se_lun->lun_stats to use atomic_long_t within the target_complete_ok_work() completion callback, and add FIXME for transport_lookup_tmr_lun() with se_lun->lun_ref. Finally, update sbp_update_unit_directory() special case usage with proper rcu_dereference_raw() and configfs symlink comment. Reported-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Cc: Paul E. McKenney Cc: Chris Boot Signed-off-by: Nicholas Bellinger --- drivers/target/sbp/sbp_target.c | 7 +- drivers/target/target_core_alua.c | 12 +++- drivers/target/target_core_device.c | 47 ++++++++----- drivers/target/target_core_file.c | 11 ++- drivers/target/target_core_iblock.c | 10 ++- drivers/target/target_core_pscsi.c | 11 ++- drivers/target/target_core_rd.c | 10 ++- drivers/target/target_core_spc.c | 2 +- drivers/target/target_core_stat.c | 123 +++++++++++++++++---------------- drivers/target/target_core_tpg.c | 16 ++--- drivers/target/target_core_transport.c | 20 ++---- drivers/target/target_core_user.c | 11 ++- include/target/target_core_base.h | 10 +-- 13 files changed, 175 insertions(+), 115 deletions(-) (limited to 'drivers') diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index 47fb12fbaf47..28e3adf1eb85 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -1905,8 +1905,11 @@ static int sbp_update_unit_directory(struct sbp_tport *tport) hlist_for_each_entry_rcu(lun, &tport->tpg->se_tpg.tpg_lun_hlist, link) { struct se_device *dev; int type; - - dev = lun->lun_se_dev; + /* + * rcu_dereference_raw protected by se_lun->lun_group symlink + * reference to se_device->dev_group. + */ + dev = rcu_dereference_raw(lun->lun_se_dev); type = dev->transport->get_device_type(dev); /* logical_unit_number */ diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 1109c2833fe6..0a0087311cfb 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -1935,7 +1935,11 @@ ssize_t core_alua_store_tg_pt_gp_info( size_t count) { struct se_portal_group *tpg = lun->lun_tpg; - struct se_device *dev = lun->lun_se_dev; + /* + * rcu_dereference_raw protected by se_lun->lun_group symlink + * reference to se_device->dev_group. + */ + struct se_device *dev = rcu_dereference_raw(lun->lun_se_dev); struct t10_alua_tg_pt_gp *tg_pt_gp = NULL, *tg_pt_gp_new = NULL; unsigned char buf[TG_PT_GROUP_NAME_BUF]; int move = 0; @@ -2189,7 +2193,11 @@ ssize_t core_alua_store_offline_bit( const char *page, size_t count) { - struct se_device *dev = lun->lun_se_dev; + /* + * rcu_dereference_raw protected by se_lun->lun_group symlink + * reference to se_device->dev_group. + */ + struct se_device *dev = rcu_dereference_raw(lun->lun_se_dev); unsigned long tmp; int ret; diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 8485e9a789fc..3baa6cd7fded 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -61,7 +61,6 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd, u32 unpacked_lun) struct se_lun *se_lun = NULL; struct se_session *se_sess = se_cmd->se_sess; struct se_node_acl *nacl = se_sess->se_node_acl; - struct se_device *dev; struct se_dev_entry *deve; if (unpacked_lun >= TRANSPORT_MAX_LUNS_PER_TPG) @@ -128,16 +127,21 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd, u32 unpacked_lun) percpu_ref_get(&se_lun->lun_ref); se_cmd->lun_ref_active = true; } + /* + * RCU reference protected by percpu se_lun->lun_ref taken above that + * must drop to zero (including initial reference) before this se_lun + * pointer can be kfree_rcu() by the final se_lun->lun_group put via + * target_core_fabric_configfs.c:target_fabric_port_release + */ + se_cmd->se_dev = rcu_dereference_raw(se_lun->lun_se_dev); + atomic_long_inc(&se_cmd->se_dev->num_cmds); - /* Directly associate cmd with se_dev */ - se_cmd->se_dev = se_lun->lun_se_dev; - - dev = se_lun->lun_se_dev; - atomic_long_inc(&dev->num_cmds); if (se_cmd->data_direction == DMA_TO_DEVICE) - atomic_long_add(se_cmd->data_length, &dev->write_bytes); + atomic_long_add(se_cmd->data_length, + &se_cmd->se_dev->write_bytes); else if (se_cmd->data_direction == DMA_FROM_DEVICE) - atomic_long_add(se_cmd->data_length, &dev->read_bytes); + atomic_long_add(se_cmd->data_length, + &se_cmd->se_dev->read_bytes); return 0; } @@ -173,10 +177,11 @@ int transport_lookup_tmr_lun(struct se_cmd *se_cmd, u32 unpacked_lun) unpacked_lun); return -ENODEV; } - - /* Directly associate cmd with se_dev */ - se_cmd->se_dev = se_lun->lun_se_dev; - se_tmr->tmr_dev = se_lun->lun_se_dev; + /* + * XXX: Add percpu se_lun->lun_ref reference count for TMR + */ + se_cmd->se_dev = rcu_dereference_raw(se_lun->lun_se_dev); + se_tmr->tmr_dev = rcu_dereference_raw(se_lun->lun_se_dev); spin_lock_irqsave(&se_tmr->tmr_dev->se_tmr_lock, flags); list_add_tail(&se_tmr->tmr_list, &se_tmr->tmr_dev->dev_tmr_list); @@ -389,6 +394,11 @@ void core_disable_device_list_for_node( struct se_node_acl *nacl, struct se_portal_group *tpg) { + /* + * rcu_dereference_raw protected by se_lun->lun_group symlink + * reference to se_device->dev_group. + */ + struct se_device *dev = rcu_dereference_raw(lun->lun_se_dev); /* * If the MappedLUN entry is being disabled, the entry in * lun->lun_deve_list must be removed now before clearing the @@ -426,7 +436,7 @@ void core_disable_device_list_for_node( kfree_rcu(orig, rcu_head); - core_scsi3_free_pr_reg_from_nacl(lun->lun_se_dev, nacl); + core_scsi3_free_pr_reg_from_nacl(dev, nacl); } /* core_clear_lun_from_tpg(): @@ -629,6 +639,11 @@ int core_dev_add_initiator_node_lun_acl( u32 lun_access) { struct se_node_acl *nacl = lacl->se_lun_nacl; + /* + * rcu_dereference_raw protected by se_lun->lun_group symlink + * reference to se_device->dev_group. + */ + struct se_device *dev = rcu_dereference_raw(lun->lun_se_dev); if (!nacl) return -EINVAL; @@ -652,7 +667,7 @@ int core_dev_add_initiator_node_lun_acl( * Check to see if there are any existing persistent reservation APTPL * pre-registrations that need to be enabled for this LUN ACL.. */ - core_scsi3_check_aptpl_registration(lun->lun_se_dev, tpg, lun, nacl, + core_scsi3_check_aptpl_registration(dev, tpg, lun, nacl, lacl->mapped_lun); return 0; } @@ -746,6 +761,7 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name) dev->se_hba = hba; dev->transport = hba->backend->ops; dev->prot_length = sizeof(struct se_dif_v1_tuple); + dev->hba_index = hba->hba_index; INIT_LIST_HEAD(&dev->dev_list); INIT_LIST_HEAD(&dev->dev_sep_list); @@ -802,8 +818,7 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name) dev->dev_attrib.max_write_same_len = DA_MAX_WRITE_SAME_LEN; xcopy_lun = &dev->xcopy_lun; - xcopy_lun->lun_se_dev = dev; - spin_lock_init(&xcopy_lun->lun_sep_lock); + rcu_assign_pointer(xcopy_lun->lun_se_dev, dev); init_completion(&xcopy_lun->lun_ref_comp); INIT_LIST_HEAD(&xcopy_lun->lun_deve_list); INIT_LIST_HEAD(&xcopy_lun->lun_dev_link); diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index 948b61f59a55..238e3a256d04 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -241,6 +241,14 @@ fail: return ret; } +static void fd_dev_call_rcu(struct rcu_head *p) +{ + struct se_device *dev = container_of(p, struct se_device, rcu_head); + struct fd_dev *fd_dev = FD_DEV(dev); + + kfree(fd_dev); +} + static void fd_free_device(struct se_device *dev) { struct fd_dev *fd_dev = FD_DEV(dev); @@ -249,8 +257,7 @@ static void fd_free_device(struct se_device *dev) filp_close(fd_dev->fd_file, NULL); fd_dev->fd_file = NULL; } - - kfree(fd_dev); + call_rcu(&dev->rcu_head, fd_dev_call_rcu); } static int fd_do_rw(struct se_cmd *cmd, struct file *fd, diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 6d4738252564..ae8ad2da6632 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -191,6 +191,14 @@ out: return ret; } +static void iblock_dev_call_rcu(struct rcu_head *p) +{ + struct se_device *dev = container_of(p, struct se_device, rcu_head); + struct iblock_dev *ib_dev = IBLOCK_DEV(dev); + + kfree(ib_dev); +} + static void iblock_free_device(struct se_device *dev) { struct iblock_dev *ib_dev = IBLOCK_DEV(dev); @@ -200,7 +208,7 @@ static void iblock_free_device(struct se_device *dev) if (ib_dev->ibd_bio_set != NULL) bioset_free(ib_dev->ibd_bio_set); - kfree(ib_dev); + call_rcu(&dev->rcu_head, iblock_dev_call_rcu); } static unsigned long long iblock_emulate_read_cap_with_block_size( diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index afb87a8d5668..c673980ded04 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -579,6 +579,14 @@ static int pscsi_configure_device(struct se_device *dev) return -ENODEV; } +static void pscsi_dev_call_rcu(struct rcu_head *p) +{ + struct se_device *dev = container_of(p, struct se_device, rcu_head); + struct pscsi_dev_virt *pdv = PSCSI_DEV(dev); + + kfree(pdv); +} + static void pscsi_free_device(struct se_device *dev) { struct pscsi_dev_virt *pdv = PSCSI_DEV(dev); @@ -610,8 +618,7 @@ static void pscsi_free_device(struct se_device *dev) pdv->pdv_sd = NULL; } - - kfree(pdv); + call_rcu(&dev->rcu_head, pscsi_dev_call_rcu); } static void pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg, diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c index 55dd73e7f213..e98432705f39 100644 --- a/drivers/target/target_core_rd.c +++ b/drivers/target/target_core_rd.c @@ -350,12 +350,20 @@ fail: return ret; } +static void rd_dev_call_rcu(struct rcu_head *p) +{ + struct se_device *dev = container_of(p, struct se_device, rcu_head); + struct rd_dev *rd_dev = RD_DEV(dev); + + kfree(rd_dev); +} + static void rd_free_device(struct se_device *dev) { struct rd_dev *rd_dev = RD_DEV(dev); rd_release_device_space(rd_dev); - kfree(rd_dev); + call_rcu(&dev->rcu_head, rd_dev_call_rcu); } static struct rd_dev_sg_table *rd_get_sg_table(struct rd_dev *rd_dev, u32 page) diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index 34d8292a4432..a2b377e06cfa 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -692,7 +692,7 @@ spc_emulate_inquiry(struct se_cmd *cmd) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } - if (dev == tpg->tpg_virt_lun0->lun_se_dev) + if (dev == rcu_access_pointer(tpg->tpg_virt_lun0->lun_se_dev)) buf[0] = 0x3f; /* Not connected */ else buf[0] = dev->transport->get_device_type(dev); diff --git a/drivers/target/target_core_stat.c b/drivers/target/target_core_stat.c index 8e080efb0188..79c785242375 100644 --- a/drivers/target/target_core_stat.c +++ b/drivers/target/target_core_stat.c @@ -545,11 +545,11 @@ static ssize_t target_stat_scsi_port_show_attr_inst( struct se_device *dev; ssize_t ret = -ENODEV; - spin_lock(&lun->lun_sep_lock); - dev = lun->lun_se_dev; + rcu_read_lock(); + dev = rcu_dereference(lun->lun_se_dev); if (dev) - ret = snprintf(page, PAGE_SIZE, "%u\n", dev->se_hba->hba_index); - spin_unlock(&lun->lun_sep_lock); + ret = snprintf(page, PAGE_SIZE, "%u\n", dev->hba_index); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_PORT_ATTR_RO(inst); @@ -561,11 +561,11 @@ static ssize_t target_stat_scsi_port_show_attr_dev( struct se_device *dev; ssize_t ret = -ENODEV; - spin_lock(&lun->lun_sep_lock); - dev = lun->lun_se_dev; + rcu_read_lock(); + dev = rcu_dereference(lun->lun_se_dev); if (dev) ret = snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index); - spin_unlock(&lun->lun_sep_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_PORT_ATTR_RO(dev); @@ -577,11 +577,11 @@ static ssize_t target_stat_scsi_port_show_attr_indx( struct se_device *dev; ssize_t ret = -ENODEV; - spin_lock(&lun->lun_sep_lock); - dev = lun->lun_se_dev; + rcu_read_lock(); + dev = rcu_dereference(lun->lun_se_dev); if (dev) ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_rtpi); - spin_unlock(&lun->lun_sep_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_PORT_ATTR_RO(indx); @@ -593,11 +593,11 @@ static ssize_t target_stat_scsi_port_show_attr_role( struct se_device *dev; ssize_t ret = -ENODEV; - spin_lock(&lun->lun_sep_lock); - dev = lun->lun_se_dev; + rcu_read_lock(); + dev = rcu_dereference(lun->lun_se_dev); if (dev) ret = snprintf(page, PAGE_SIZE, "%s%u\n", "Device", dev->dev_index); - spin_unlock(&lun->lun_sep_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_PORT_ATTR_RO(role); @@ -609,13 +609,13 @@ static ssize_t target_stat_scsi_port_show_attr_busy_count( struct se_device *dev; ssize_t ret = -ENODEV; - spin_lock(&lun->lun_sep_lock); - dev = lun->lun_se_dev; + rcu_read_lock(); + dev = rcu_dereference(lun->lun_se_dev); if (dev) { /* FIXME: scsiPortBusyStatuses */ ret = snprintf(page, PAGE_SIZE, "%u\n", 0); } - spin_unlock(&lun->lun_sep_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_PORT_ATTR_RO(busy_count); @@ -666,11 +666,11 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_inst( struct se_device *dev; ssize_t ret = -ENODEV; - spin_lock(&lun->lun_sep_lock); - dev = lun->lun_se_dev; + rcu_read_lock(); + dev = rcu_dereference(lun->lun_se_dev); if (dev) - ret = snprintf(page, PAGE_SIZE, "%u\n", dev->se_hba->hba_index); - spin_unlock(&lun->lun_sep_lock); + ret = snprintf(page, PAGE_SIZE, "%u\n", dev->hba_index); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_TGT_PORT_ATTR_RO(inst); @@ -682,11 +682,11 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_dev( struct se_device *dev; ssize_t ret = -ENODEV; - spin_lock(&lun->lun_sep_lock); - dev = lun->lun_se_dev; + rcu_read_lock(); + dev = rcu_dereference(lun->lun_se_dev); if (dev) ret = snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index); - spin_unlock(&lun->lun_sep_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_TGT_PORT_ATTR_RO(dev); @@ -698,11 +698,11 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_indx( struct se_device *dev; ssize_t ret = -ENODEV; - spin_lock(&lun->lun_sep_lock); - dev = lun->lun_se_dev; + rcu_read_lock(); + dev = rcu_dereference(lun->lun_se_dev); if (dev) ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_rtpi); - spin_unlock(&lun->lun_sep_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_TGT_PORT_ATTR_RO(indx); @@ -715,13 +715,13 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_name( struct se_device *dev; ssize_t ret = -ENODEV; - spin_lock(&lun->lun_sep_lock); - dev = lun->lun_se_dev; + rcu_read_lock(); + dev = rcu_dereference(lun->lun_se_dev); if (dev) ret = snprintf(page, PAGE_SIZE, "%sPort#%u\n", tpg->se_tpg_tfo->get_fabric_name(), lun->lun_rtpi); - spin_unlock(&lun->lun_sep_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_TGT_PORT_ATTR_RO(name); @@ -734,13 +734,13 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_port_index( struct se_device *dev; ssize_t ret = -ENODEV; - spin_lock(&lun->lun_sep_lock); - dev = lun->lun_se_dev; + rcu_read_lock(); + dev = rcu_dereference(lun->lun_se_dev); if (dev) ret = snprintf(page, PAGE_SIZE, "%s%s%d\n", tpg->se_tpg_tfo->tpg_get_wwn(tpg), "+t+", tpg->se_tpg_tfo->tpg_get_tag(tpg)); - spin_unlock(&lun->lun_sep_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_TGT_PORT_ATTR_RO(port_index); @@ -752,11 +752,12 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_in_cmds( struct se_device *dev; ssize_t ret = -ENODEV; - spin_lock(&lun->lun_sep_lock); - dev = lun->lun_se_dev; + rcu_read_lock(); + dev = rcu_dereference(lun->lun_se_dev); if (dev) - ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_stats.cmd_pdus); - spin_unlock(&lun->lun_sep_lock); + ret = snprintf(page, PAGE_SIZE, "%lu\n", + atomic_long_read(&lun->lun_stats.cmd_pdus)); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_TGT_PORT_ATTR_RO(in_cmds); @@ -768,12 +769,12 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_write_mbytes( struct se_device *dev; ssize_t ret = -ENODEV; - spin_lock(&lun->lun_sep_lock); - dev = lun->lun_se_dev; + rcu_read_lock(); + dev = rcu_dereference(lun->lun_se_dev); if (dev) ret = snprintf(page, PAGE_SIZE, "%u\n", - (u32)(lun->lun_stats.rx_data_octets >> 20)); - spin_unlock(&lun->lun_sep_lock); + (u32)(atomic_long_read(&lun->lun_stats.rx_data_octets) >> 20)); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_TGT_PORT_ATTR_RO(write_mbytes); @@ -785,12 +786,12 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_read_mbytes( struct se_device *dev; ssize_t ret = -ENODEV; - spin_lock(&lun->lun_sep_lock); - dev = lun->lun_se_dev; + rcu_read_lock(); + dev = rcu_dereference(lun->lun_se_dev); if (dev) ret = snprintf(page, PAGE_SIZE, "%u\n", - (u32)(lun->lun_stats.tx_data_octets >> 20)); - spin_unlock(&lun->lun_sep_lock); + (u32)(atomic_long_read(&lun->lun_stats.tx_data_octets) >> 20)); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_TGT_PORT_ATTR_RO(read_mbytes); @@ -802,13 +803,13 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_hs_in_cmds( struct se_device *dev; ssize_t ret = -ENODEV; - spin_lock(&lun->lun_sep_lock); - dev = lun->lun_se_dev; + rcu_read_lock(); + dev = rcu_dereference(lun->lun_se_dev); if (dev) { /* FIXME: scsiTgtPortHsInCommands */ ret = snprintf(page, PAGE_SIZE, "%u\n", 0); } - spin_unlock(&lun->lun_sep_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_TGT_PORT_ATTR_RO(hs_in_cmds); @@ -865,11 +866,11 @@ static ssize_t target_stat_scsi_transport_show_attr_inst( struct se_device *dev; ssize_t ret = -ENODEV; - spin_lock(&lun->lun_sep_lock); - dev = lun->lun_se_dev; + rcu_read_lock(); + dev = rcu_dereference(lun->lun_se_dev); if (dev) - ret = snprintf(page, PAGE_SIZE, "%u\n", dev->se_hba->hba_index); - spin_unlock(&lun->lun_sep_lock); + ret = snprintf(page, PAGE_SIZE, "%u\n", dev->hba_index); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_TRANSPORT_ATTR_RO(inst); @@ -882,14 +883,14 @@ static ssize_t target_stat_scsi_transport_show_attr_device( struct se_portal_group *tpg = lun->lun_tpg; ssize_t ret = -ENODEV; - spin_lock(&lun->lun_sep_lock); - dev = lun->lun_se_dev; + rcu_read_lock(); + dev = rcu_dereference(lun->lun_se_dev); if (dev) { /* scsiTransportType */ ret = snprintf(page, PAGE_SIZE, "scsiTransport%s\n", tpg->se_tpg_tfo->get_fabric_name()); } - spin_unlock(&lun->lun_sep_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_TRANSPORT_ATTR_RO(device); @@ -902,12 +903,12 @@ static ssize_t target_stat_scsi_transport_show_attr_indx( struct se_portal_group *tpg = lun->lun_tpg; ssize_t ret = -ENODEV; - spin_lock(&lun->lun_sep_lock); - dev = lun->lun_se_dev; + rcu_read_lock(); + dev = rcu_dereference(lun->lun_se_dev); if (dev) ret = snprintf(page, PAGE_SIZE, "%u\n", tpg->se_tpg_tfo->tpg_get_inst_index(tpg)); - spin_unlock(&lun->lun_sep_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_TRANSPORT_ATTR_RO(indx); @@ -916,13 +917,13 @@ static ssize_t target_stat_scsi_transport_show_attr_dev_name( struct se_port_stat_grps *pgrps, char *page) { struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); - struct se_device *dev = lun->lun_se_dev; + struct se_device *dev; struct se_portal_group *tpg = lun->lun_tpg; struct t10_wwn *wwn; ssize_t ret = -ENODEV; - spin_lock(&lun->lun_sep_lock); - dev = lun->lun_se_dev; + rcu_read_lock(); + dev = rcu_dereference(lun->lun_se_dev); if (dev) { wwn = &dev->t10_wwn; /* scsiTransportDevName */ @@ -931,7 +932,7 @@ static ssize_t target_stat_scsi_transport_show_attr_dev_name( (strlen(wwn->unit_serial)) ? wwn->unit_serial : wwn->vendor); } - spin_unlock(&lun->lun_sep_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_TRANSPORT_ATTR_RO(dev_name); diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index 499b1399035a..5b30940ccaf2 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -102,7 +102,8 @@ void core_tpg_add_node_to_devs( if (lun_orig && lun != lun_orig) continue; - dev = lun->lun_se_dev; + dev = rcu_dereference_check(lun->lun_se_dev, + lockdep_is_held(&tpg->tpg_lun_mutex)); /* * By default in LIO-Target $FABRIC_MOD, * demo_mode_write_protect is ON, or READ_ONLY; @@ -598,7 +599,6 @@ struct se_lun *core_tpg_alloc_lun( lun->unpacked_lun = unpacked_lun; lun->lun_link_magic = SE_LUN_LINK_MAGIC; atomic_set(&lun->lun_acl_count, 0); - spin_lock_init(&lun->lun_sep_lock); init_completion(&lun->lun_ref_comp); INIT_LIST_HEAD(&lun->lun_deve_list); INIT_LIST_HEAD(&lun->lun_dev_link); @@ -636,12 +636,8 @@ int core_tpg_add_lun( mutex_lock(&tpg->tpg_lun_mutex); - spin_lock(&lun->lun_sep_lock); - lun->lun_index = dev->dev_index; - lun->lun_se_dev = dev; - spin_unlock(&lun->lun_sep_lock); - spin_lock(&dev->se_port_lock); + lun->lun_index = dev->dev_index; rcu_assign_pointer(lun->lun_se_dev, dev); dev->export_count++; list_add_tail(&lun->lun_dev_link, &dev->dev_sep_list); @@ -664,7 +660,11 @@ void core_tpg_remove_lun( struct se_portal_group *tpg, struct se_lun *lun) { - struct se_device *dev = lun->lun_se_dev; + /* + * rcu_dereference_raw protected by se_lun->lun_group symlink + * reference to se_device->dev_group. + */ + struct se_device *dev = rcu_dereference_raw(lun->lun_se_dev); core_clear_lun_from_tpg(lun, tpg); transport_clear_lun_ref(lun); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index ef6fdd8a47c4..d8a59122fe3b 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1261,10 +1261,7 @@ target_setup_cmd_from_cdb(struct se_cmd *cmd, unsigned char *cdb) return ret; cmd->se_cmd_flags |= SCF_SUPPORTED_SAM_OPCODE; - - spin_lock(&cmd->se_lun->lun_sep_lock); - cmd->se_lun->lun_stats.cmd_pdus++; - spin_unlock(&cmd->se_lun->lun_sep_lock); + atomic_long_inc(&cmd->se_lun->lun_stats.cmd_pdus); return 0; } EXPORT_SYMBOL(target_setup_cmd_from_cdb); @@ -2060,9 +2057,8 @@ static void target_complete_ok_work(struct work_struct *work) queue_rsp: switch (cmd->data_direction) { case DMA_FROM_DEVICE: - spin_lock(&cmd->se_lun->lun_sep_lock); - cmd->se_lun->lun_stats.tx_data_octets += cmd->data_length; - spin_unlock(&cmd->se_lun->lun_sep_lock); + atomic_long_add(cmd->data_length, + &cmd->se_lun->lun_stats.tx_data_octets); /* * Perform READ_STRIP of PI using software emulation when * backend had PI enabled, if the transport will not be @@ -2085,16 +2081,14 @@ queue_rsp: goto queue_full; break; case DMA_TO_DEVICE: - spin_lock(&cmd->se_lun->lun_sep_lock); - cmd->se_lun->lun_stats.rx_data_octets += cmd->data_length; - spin_unlock(&cmd->se_lun->lun_sep_lock); + atomic_long_add(cmd->data_length, + &cmd->se_lun->lun_stats.rx_data_octets); /* * Check if we need to send READ payload for BIDI-COMMAND */ if (cmd->se_cmd_flags & SCF_BIDI) { - spin_lock(&cmd->se_lun->lun_sep_lock); - cmd->se_lun->lun_stats.tx_data_octets += cmd->data_length; - spin_unlock(&cmd->se_lun->lun_sep_lock); + atomic_long_add(cmd->data_length, + &cmd->se_lun->lun_stats.tx_data_octets); ret = cmd->se_tfo->queue_data_in(cmd); if (ret == -EAGAIN || ret == -ENOMEM) goto queue_full; diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index aebaad55e23f..949e6165ef8a 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -950,6 +950,14 @@ static int tcmu_check_pending_cmd(int id, void *p, void *data) return -EINVAL; } +static void tcmu_dev_call_rcu(struct rcu_head *p) +{ + struct se_device *dev = container_of(p, struct se_device, rcu_head); + struct tcmu_dev *udev = TCMU_DEV(dev); + + kfree(udev); +} + static void tcmu_free_device(struct se_device *dev) { struct tcmu_dev *udev = TCMU_DEV(dev); @@ -975,8 +983,7 @@ static void tcmu_free_device(struct se_device *dev) kfree(udev->uio_info.name); kfree(udev->name); } - - kfree(udev); + call_rcu(&dev->rcu_head, tcmu_dev_call_rcu); } enum { diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 1927dd5947a7..b82a989a4d3b 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -690,9 +690,9 @@ struct se_port_stat_grps { }; struct scsi_port_stats { - u32 cmd_pdus; - u64 tx_data_octets; - u64 rx_data_octets; + atomic_long_t cmd_pdus; + atomic_long_t tx_data_octets; + atomic_long_t rx_data_octets; }; struct se_lun { @@ -705,7 +705,6 @@ struct se_lun { u32 unpacked_lun; u32 lun_index; atomic_t lun_acl_count; - spinlock_t lun_sep_lock; struct se_device __rcu *lun_se_dev; struct list_head lun_deve_list; @@ -818,6 +817,9 @@ struct se_device { struct se_lun xcopy_lun; /* Protection Information */ int prot_length; + /* For se_lun->lun_se_dev RCU read-side critical access */ + u32 hba_index; + struct rcu_head rcu_head; }; struct se_hba { -- cgit v1.2.3-70-g09d2 From 9e37d042cfcb003b885bb4c531cd6f07f62647d1 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Wed, 20 May 2015 21:21:08 -0700 Subject: target: Drop se_lun->lun_active for existing percpu lun_ref With se_port_t and t10_alua_tg_pt_gp_member being absored into se_lun, there is no need for an extra atomic_t based reference count for PR ALL_TG_PT=1 and ALUA access state transition. Go ahead and use the existing percpu se_lun->lun_ref instead, and convert the two special cases to percpu_ref_tryget_live() to avoid se_lun if transport_clear_lun_ref() has already been invoked to shutdown the se_lun. Cc: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_alua.c | 5 +++-- drivers/target/target_core_pr.c | 9 +++++---- drivers/target/target_core_tpg.c | 10 ++++++---- include/target/target_core_base.h | 1 - 4 files changed, 14 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 0a0087311cfb..02d8e1a8a6a5 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -969,7 +969,8 @@ static void core_alua_do_transition_tg_pt_work(struct work_struct *work) * every I_T nexus other than the I_T nexus on which the SET * TARGET PORT GROUPS command */ - atomic_inc_mb(&lun->lun_active); + if (!percpu_ref_tryget_live(&lun->lun_ref)) + continue; spin_unlock(&tg_pt_gp->tg_pt_gp_lock); spin_lock_bh(&lun->lun_deve_lock); @@ -998,7 +999,7 @@ static void core_alua_do_transition_tg_pt_work(struct work_struct *work) spin_unlock_bh(&lun->lun_deve_lock); spin_lock(&tg_pt_gp->tg_pt_gp_lock); - atomic_dec_mb(&lun->lun_active); + percpu_ref_put(&lun->lun_ref); } spin_unlock(&tg_pt_gp->tg_pt_gp_lock); /* diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 60624bb6c598..94935eaa7fa7 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -704,7 +704,8 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( */ spin_lock(&dev->se_port_lock); list_for_each_entry_safe(lun_tmp, next, &dev->dev_sep_list, lun_dev_link) { - atomic_inc_mb(&lun_tmp->lun_active); + if (!percpu_ref_tryget_live(&lun_tmp->lun_ref)) + continue; spin_unlock(&dev->se_port_lock); spin_lock_bh(&lun_tmp->lun_deve_lock); @@ -751,7 +752,7 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( if (ret < 0) { pr_err("core_scsi3_lunacl_depend" "_item() failed\n"); - atomic_dec_mb(&lun->lun_active); + percpu_ref_put(&lun_tmp->lun_ref); kref_put(&deve_tmp->pr_kref, target_pr_kref_release); goto out; } @@ -770,7 +771,7 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( deve_tmp->mapped_lun, NULL, sa_res_key, all_tg_pt, aptpl); if (!pr_reg_atp) { - atomic_dec_mb(&lun_tmp->lun_active); + percpu_ref_put(&lun_tmp->lun_ref); core_scsi3_lunacl_undepend_item(deve_tmp); goto out; } @@ -782,7 +783,7 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( spin_unlock_bh(&lun_tmp->lun_deve_lock); spin_lock(&dev->se_port_lock); - atomic_dec_mb(&lun_tmp->lun_active); + percpu_ref_put(&lun_tmp->lun_ref); } spin_unlock(&dev->se_port_lock); diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index 5b30940ccaf2..b9fcf2c4898e 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -607,7 +607,6 @@ struct se_lun *core_tpg_alloc_lun( mutex_init(&lun->lun_tg_pt_md_mutex); INIT_LIST_HEAD(&lun->lun_tg_pt_gp_link); spin_lock_init(&lun->lun_tg_pt_gp_lock); - atomic_set(&lun->lun_active, 0); lun->lun_tpg = tpg; return lun; @@ -667,13 +666,16 @@ void core_tpg_remove_lun( struct se_device *dev = rcu_dereference_raw(lun->lun_se_dev); core_clear_lun_from_tpg(lun, tpg); + /* + * Wait for any active I/O references to percpu se_lun->lun_ref to + * be released. Also, se_lun->lun_ref is now used by PR and ALUA + * logic when referencing a remote target port during ALL_TGT_PT=1 + * and generating UNIT_ATTENTIONs for ALUA access state transition. + */ transport_clear_lun_ref(lun); mutex_lock(&tpg->tpg_lun_mutex); if (lun->lun_se_dev) { - while (atomic_read(&lun->lun_active)) - cpu_relax(); - target_detach_tg_pt_gp(lun); spin_lock(&dev->se_port_lock); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index b82a989a4d3b..eefc2b0cfaa3 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -721,7 +721,6 @@ struct se_lun { struct t10_alua_tg_pt_gp *lun_tg_pt_gp; spinlock_t lun_tg_pt_gp_lock; - atomic_t lun_active; struct se_portal_group *lun_tpg; struct scsi_port_stats lun_stats; struct config_group lun_group; -- cgit v1.2.3-70-g09d2 From 25bd55bbabd8957693c1ffc2fe1bf16cb4fdabd4 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Fri, 24 Apr 2015 14:24:38 +0200 Subject: tun: add tun_is_little_endian() helper Signed-off-by: Greg Kurz Signed-off-by: Michael S. Tsirkin Acked-by: Cornelia Huck Reviewed-by: David Gibson --- drivers/net/tun.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tun.c b/drivers/net/tun.c index e470ae59d405..301e87c89a9f 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -206,14 +206,19 @@ struct tun_struct { u32 flow_count; }; +static inline bool tun_is_little_endian(struct tun_struct *tun) +{ + return tun->flags & TUN_VNET_LE; +} + static inline u16 tun16_to_cpu(struct tun_struct *tun, __virtio16 val) { - return __virtio16_to_cpu(tun->flags & TUN_VNET_LE, val); + return __virtio16_to_cpu(tun_is_little_endian(tun), val); } static inline __virtio16 cpu_to_tun16(struct tun_struct *tun, u16 val) { - return __cpu_to_virtio16(tun->flags & TUN_VNET_LE, val); + return __cpu_to_virtio16(tun_is_little_endian(tun), val); } static inline u32 tun_hashfn(u32 rxhash) -- cgit v1.2.3-70-g09d2 From 5b11e15f24744d2ea6210451529d2b180337965a Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Fri, 24 Apr 2015 14:24:48 +0200 Subject: macvtap: introduce macvtap_is_little_endian() helper Signed-off-by: Greg Kurz Signed-off-by: Michael S. Tsirkin Acked-by: Cornelia Huck Reviewed-by: David Gibson --- drivers/net/macvtap.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 8c350c5d54ad..4fdb88102082 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -49,14 +49,19 @@ struct macvtap_queue { #define MACVTAP_VNET_LE 0x80000000 +static inline bool macvtap_is_little_endian(struct macvtap_queue *q) +{ + return q->flags & MACVTAP_VNET_LE; +} + static inline u16 macvtap16_to_cpu(struct macvtap_queue *q, __virtio16 val) { - return __virtio16_to_cpu(q->flags & MACVTAP_VNET_LE, val); + return __virtio16_to_cpu(macvtap_is_little_endian(q), val); } static inline __virtio16 cpu_to_macvtap16(struct macvtap_queue *q, u16 val) { - return __cpu_to_virtio16(q->flags & MACVTAP_VNET_LE, val); + return __cpu_to_virtio16(macvtap_is_little_endian(q), val); } static struct proto macvtap_proto = { -- cgit v1.2.3-70-g09d2 From ab27c07f607253f928cbc8c64d9c0d273df09e6b Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Fri, 24 Apr 2015 14:25:12 +0200 Subject: vhost: introduce vhost_is_little_endian() helper Signed-off-by: Greg Kurz Signed-off-by: Michael S. Tsirkin Acked-by: Cornelia Huck Reviewed-by: David Gibson --- drivers/vhost/vhost.h | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index 8c1c792900ba..6a499603d856 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -173,34 +173,39 @@ static inline bool vhost_has_feature(struct vhost_virtqueue *vq, int bit) return vq->acked_features & (1ULL << bit); } +static inline bool vhost_is_little_endian(struct vhost_virtqueue *vq) +{ + return vhost_has_feature(vq, VIRTIO_F_VERSION_1); +} + /* Memory accessors */ static inline u16 vhost16_to_cpu(struct vhost_virtqueue *vq, __virtio16 val) { - return __virtio16_to_cpu(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val); + return __virtio16_to_cpu(vhost_is_little_endian(vq), val); } static inline __virtio16 cpu_to_vhost16(struct vhost_virtqueue *vq, u16 val) { - return __cpu_to_virtio16(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val); + return __cpu_to_virtio16(vhost_is_little_endian(vq), val); } static inline u32 vhost32_to_cpu(struct vhost_virtqueue *vq, __virtio32 val) { - return __virtio32_to_cpu(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val); + return __virtio32_to_cpu(vhost_is_little_endian(vq), val); } static inline __virtio32 cpu_to_vhost32(struct vhost_virtqueue *vq, u32 val) { - return __cpu_to_virtio32(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val); + return __cpu_to_virtio32(vhost_is_little_endian(vq), val); } static inline u64 vhost64_to_cpu(struct vhost_virtqueue *vq, __virtio64 val) { - return __virtio64_to_cpu(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val); + return __virtio64_to_cpu(vhost_is_little_endian(vq), val); } static inline __virtio64 cpu_to_vhost64(struct vhost_virtqueue *vq, u64 val) { - return __cpu_to_virtio64(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val); + return __cpu_to_virtio64(vhost_is_little_endian(vq), val); } #endif -- cgit v1.2.3-70-g09d2 From 7d82410950aa74adccf035c332e409af2bb93e92 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Fri, 24 Apr 2015 14:26:24 +0200 Subject: virtio: add explicit big-endian support to memory accessors The current memory accessors logic is: - little endian if little_endian - native endian (i.e. no byteswap) if !little_endian If we want to fully support cross-endian vhost, we also need to be able to convert to big endian. Instead of changing the little_endian argument to some 3-value enum, this patch changes the logic to: - little endian if little_endian - big endian if !little_endian The native endian case is handled by all users with a trivial helper. This patch doesn't change any functionality, nor it does add overhead. Signed-off-by: Greg Kurz Signed-off-by: Michael S. Tsirkin Reviewed-by: Cornelia Huck Reviewed-by: David Gibson --- drivers/net/macvtap.c | 3 ++- drivers/net/tun.c | 3 ++- drivers/vhost/vhost.h | 3 ++- include/linux/virtio_byteorder.h | 24 ++++++++++++++---------- include/linux/virtio_config.h | 3 ++- include/linux/vringh.h | 3 ++- 6 files changed, 24 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 4fdb88102082..072ccbaf7c45 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -51,7 +51,8 @@ struct macvtap_queue { static inline bool macvtap_is_little_endian(struct macvtap_queue *q) { - return q->flags & MACVTAP_VNET_LE; + return q->flags & MACVTAP_VNET_LE || + virtio_legacy_is_little_endian(); } static inline u16 macvtap16_to_cpu(struct macvtap_queue *q, __virtio16 val) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 301e87c89a9f..b210139bef8f 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -208,7 +208,8 @@ struct tun_struct { static inline bool tun_is_little_endian(struct tun_struct *tun) { - return tun->flags & TUN_VNET_LE; + return tun->flags & TUN_VNET_LE || + virtio_legacy_is_little_endian(); } static inline u16 tun16_to_cpu(struct tun_struct *tun, __virtio16 val) diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index 6a499603d856..a4fa33a79bf2 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -175,7 +175,8 @@ static inline bool vhost_has_feature(struct vhost_virtqueue *vq, int bit) static inline bool vhost_is_little_endian(struct vhost_virtqueue *vq) { - return vhost_has_feature(vq, VIRTIO_F_VERSION_1); + return vhost_has_feature(vq, VIRTIO_F_VERSION_1) || + virtio_legacy_is_little_endian(); } /* Memory accessors */ diff --git a/include/linux/virtio_byteorder.h b/include/linux/virtio_byteorder.h index 51865d05b267..ce63a2c3a612 100644 --- a/include/linux/virtio_byteorder.h +++ b/include/linux/virtio_byteorder.h @@ -3,17 +3,21 @@ #include #include -/* - * Low-level memory accessors for handling virtio in modern little endian and in - * compatibility native endian format. - */ +static inline bool virtio_legacy_is_little_endian(void) +{ +#ifdef __LITTLE_ENDIAN + return true; +#else + return false; +#endif +} static inline u16 __virtio16_to_cpu(bool little_endian, __virtio16 val) { if (little_endian) return le16_to_cpu((__force __le16)val); else - return (__force u16)val; + return be16_to_cpu((__force __be16)val); } static inline __virtio16 __cpu_to_virtio16(bool little_endian, u16 val) @@ -21,7 +25,7 @@ static inline __virtio16 __cpu_to_virtio16(bool little_endian, u16 val) if (little_endian) return (__force __virtio16)cpu_to_le16(val); else - return (__force __virtio16)val; + return (__force __virtio16)cpu_to_be16(val); } static inline u32 __virtio32_to_cpu(bool little_endian, __virtio32 val) @@ -29,7 +33,7 @@ static inline u32 __virtio32_to_cpu(bool little_endian, __virtio32 val) if (little_endian) return le32_to_cpu((__force __le32)val); else - return (__force u32)val; + return be32_to_cpu((__force __be32)val); } static inline __virtio32 __cpu_to_virtio32(bool little_endian, u32 val) @@ -37,7 +41,7 @@ static inline __virtio32 __cpu_to_virtio32(bool little_endian, u32 val) if (little_endian) return (__force __virtio32)cpu_to_le32(val); else - return (__force __virtio32)val; + return (__force __virtio32)cpu_to_be32(val); } static inline u64 __virtio64_to_cpu(bool little_endian, __virtio64 val) @@ -45,7 +49,7 @@ static inline u64 __virtio64_to_cpu(bool little_endian, __virtio64 val) if (little_endian) return le64_to_cpu((__force __le64)val); else - return (__force u64)val; + return be64_to_cpu((__force __be64)val); } static inline __virtio64 __cpu_to_virtio64(bool little_endian, u64 val) @@ -53,7 +57,7 @@ static inline __virtio64 __cpu_to_virtio64(bool little_endian, u64 val) if (little_endian) return (__force __virtio64)cpu_to_le64(val); else - return (__force __virtio64)val; + return (__force __virtio64)cpu_to_be64(val); } #endif /* _LINUX_VIRTIO_BYTEORDER */ diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h index 170947eb11b5..e5ce8ab0b8b0 100644 --- a/include/linux/virtio_config.h +++ b/include/linux/virtio_config.h @@ -207,7 +207,8 @@ int virtqueue_set_affinity(struct virtqueue *vq, int cpu) static inline bool virtio_is_little_endian(struct virtio_device *vdev) { - return virtio_has_feature(vdev, VIRTIO_F_VERSION_1); + return virtio_has_feature(vdev, VIRTIO_F_VERSION_1) || + virtio_legacy_is_little_endian(); } /* Memory accessors */ diff --git a/include/linux/vringh.h b/include/linux/vringh.h index 3ed62efc2bc5..bc6c28d04263 100644 --- a/include/linux/vringh.h +++ b/include/linux/vringh.h @@ -228,7 +228,8 @@ static inline void vringh_notify(struct vringh *vrh) static inline bool vringh_is_little_endian(const struct vringh *vrh) { - return vrh->little_endian; + return vrh->little_endian || + virtio_legacy_is_little_endian(); } static inline u16 vringh16_to_cpu(const struct vringh *vrh, __virtio16 val) -- cgit v1.2.3-70-g09d2 From 2751c9882b947292fcfb084c4f604e01724af804 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Fri, 24 Apr 2015 14:27:24 +0200 Subject: vhost: cross-endian support for legacy devices This patch brings cross-endian support to vhost when used to implement legacy virtio devices. Since it is a relatively rare situation, the feature availability is controlled by a kernel config option (not set by default). The vq->is_le boolean field is added to cache the endianness to be used for ring accesses. It defaults to native endian, as expected by legacy virtio devices. When the ring gets active, we force little endian if the device is modern. When the ring is deactivated, we revert to the native endian default. If cross-endian was compiled in, a vq->user_be boolean field is added so that userspace may request a specific endianness. This field is used to override the default when activating the ring of a legacy device. It has no effect on modern devices. Signed-off-by: Greg Kurz Signed-off-by: Michael S. Tsirkin Reviewed-by: Cornelia Huck Reviewed-by: David Gibson --- drivers/vhost/Kconfig | 15 ++++++++ drivers/vhost/vhost.c | 85 +++++++++++++++++++++++++++++++++++++++++++++- drivers/vhost/vhost.h | 11 ++++-- include/uapi/linux/vhost.h | 14 ++++++++ 4 files changed, 122 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/vhost/Kconfig b/drivers/vhost/Kconfig index 017a1e8a8f6f..533eaf04f12f 100644 --- a/drivers/vhost/Kconfig +++ b/drivers/vhost/Kconfig @@ -32,3 +32,18 @@ config VHOST ---help--- This option is selected by any driver which needs to access the core of vhost. + +config VHOST_CROSS_ENDIAN_LEGACY + bool "Cross-endian support for vhost" + default n + ---help--- + This option allows vhost to support guests with a different byte + ordering from host while using legacy virtio. + + Userspace programs can control the feature using the + VHOST_SET_VRING_ENDIAN and VHOST_GET_VRING_ENDIAN ioctls. + + This is only useful on a few platforms (ppc64 and arm64). Since it + adds some overhead, it is disabled by default. + + If unsure, say "N". diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 2ee28266fd07..9e8e004bb1c3 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -36,6 +36,77 @@ enum { #define vhost_used_event(vq) ((__virtio16 __user *)&vq->avail->ring[vq->num]) #define vhost_avail_event(vq) ((__virtio16 __user *)&vq->used->ring[vq->num]) +#ifdef CONFIG_VHOST_CROSS_ENDIAN_LEGACY +static void vhost_vq_reset_user_be(struct vhost_virtqueue *vq) +{ + vq->user_be = !virtio_legacy_is_little_endian(); +} + +static long vhost_set_vring_endian(struct vhost_virtqueue *vq, int __user *argp) +{ + struct vhost_vring_state s; + + if (vq->private_data) + return -EBUSY; + + if (copy_from_user(&s, argp, sizeof(s))) + return -EFAULT; + + if (s.num != VHOST_VRING_LITTLE_ENDIAN && + s.num != VHOST_VRING_BIG_ENDIAN) + return -EINVAL; + + vq->user_be = s.num; + + return 0; +} + +static long vhost_get_vring_endian(struct vhost_virtqueue *vq, u32 idx, + int __user *argp) +{ + struct vhost_vring_state s = { + .index = idx, + .num = vq->user_be + }; + + if (copy_to_user(argp, &s, sizeof(s))) + return -EFAULT; + + return 0; +} + +static void vhost_init_is_le(struct vhost_virtqueue *vq) +{ + /* Note for legacy virtio: user_be is initialized at reset time + * according to the host endianness. If userspace does not set an + * explicit endianness, the default behavior is native endian, as + * expected by legacy virtio. + */ + vq->is_le = vhost_has_feature(vq, VIRTIO_F_VERSION_1) || !vq->user_be; +} +#else +static void vhost_vq_reset_user_be(struct vhost_virtqueue *vq) +{ +} + +static long vhost_set_vring_endian(struct vhost_virtqueue *vq, int __user *argp) +{ + return -ENOIOCTLCMD; +} + +static long vhost_get_vring_endian(struct vhost_virtqueue *vq, u32 idx, + int __user *argp) +{ + return -ENOIOCTLCMD; +} + +static void vhost_init_is_le(struct vhost_virtqueue *vq) +{ + if (vhost_has_feature(vq, VIRTIO_F_VERSION_1)) + vq->is_le = true; +} +#endif /* CONFIG_VHOST_CROSS_ENDIAN_LEGACY */ + static void vhost_poll_func(struct file *file, wait_queue_head_t *wqh, poll_table *pt) { @@ -199,6 +270,8 @@ static void vhost_vq_reset(struct vhost_dev *dev, vq->call = NULL; vq->log_ctx = NULL; vq->memory = NULL; + vq->is_le = virtio_legacy_is_little_endian(); + vhost_vq_reset_user_be(vq); } static int vhost_worker(void *data) @@ -806,6 +879,12 @@ long vhost_vring_ioctl(struct vhost_dev *d, int ioctl, void __user *argp) } else filep = eventfp; break; + case VHOST_SET_VRING_ENDIAN: + r = vhost_set_vring_endian(vq, argp); + break; + case VHOST_GET_VRING_ENDIAN: + r = vhost_get_vring_endian(vq, idx, argp); + break; default: r = -ENOIOCTLCMD; } @@ -1044,8 +1123,12 @@ int vhost_init_used(struct vhost_virtqueue *vq) { __virtio16 last_used_idx; int r; - if (!vq->private_data) + if (!vq->private_data) { + vq->is_le = virtio_legacy_is_little_endian(); return 0; + } + + vhost_init_is_le(vq); r = vhost_update_used_flags(vq); if (r) diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index a4fa33a79bf2..ce6f6da4b09f 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -106,6 +106,14 @@ struct vhost_virtqueue { /* Log write descriptors */ void __user *log_base; struct vhost_log *log; + + /* Ring endianness. Defaults to legacy native endianness. + * Set to true when starting a modern virtio device. */ + bool is_le; +#ifdef CONFIG_VHOST_CROSS_ENDIAN_LEGACY + /* Ring endianness requested by userspace for cross-endian support. */ + bool user_be; +#endif }; struct vhost_dev { @@ -175,8 +183,7 @@ static inline bool vhost_has_feature(struct vhost_virtqueue *vq, int bit) static inline bool vhost_is_little_endian(struct vhost_virtqueue *vq) { - return vhost_has_feature(vq, VIRTIO_F_VERSION_1) || - virtio_legacy_is_little_endian(); + return vq->is_le; } /* Memory accessors */ diff --git a/include/uapi/linux/vhost.h b/include/uapi/linux/vhost.h index bb6a5b4cb3c5..ab3731917bac 100644 --- a/include/uapi/linux/vhost.h +++ b/include/uapi/linux/vhost.h @@ -103,6 +103,20 @@ struct vhost_memory { /* Get accessor: reads index, writes value in num */ #define VHOST_GET_VRING_BASE _IOWR(VHOST_VIRTIO, 0x12, struct vhost_vring_state) +/* Set the vring byte order in num. Valid values are VHOST_VRING_LITTLE_ENDIAN + * or VHOST_VRING_BIG_ENDIAN (other values return -EINVAL). + * The byte order cannot be changed while the device is active: trying to do so + * returns -EBUSY. + * This is a legacy only API that is simply ignored when VIRTIO_F_VERSION_1 is + * set. + * Not all kernel configurations support this ioctl, but all configurations that + * support SET also support GET. + */ +#define VHOST_VRING_LITTLE_ENDIAN 0 +#define VHOST_VRING_BIG_ENDIAN 1 +#define VHOST_SET_VRING_ENDIAN _IOW(VHOST_VIRTIO, 0x13, struct vhost_vring_state) +#define VHOST_GET_VRING_ENDIAN _IOW(VHOST_VIRTIO, 0x14, struct vhost_vring_state) + /* The following ioctls use eventfd file descriptors to signal and poll * for events. */ -- cgit v1.2.3-70-g09d2 From 8b8e658b16336f0f50aba733f51db636ef121f50 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Fri, 24 Apr 2015 14:50:36 +0200 Subject: macvtap/tun: cross-endian support for little-endian hosts The VNET_LE flag was introduced to fix accesses to virtio 1.0 headers that are always little-endian. It can also be used to handle the special case of a legacy little-endian device implemented by a big-endian host. Let's add a flag and ioctls for big-endian devices as well. If both flags are set, little-endian wins. Since this is isn't a common usecase, the feature is controlled by a kernel config option (not set by default). Both macvtap and tun are covered by this patch since they share the same API with userland. Signed-off-by: Greg Kurz Signed-off-by: Michael S. Tsirkin Reviewed-by: David Gibson --- drivers/net/Kconfig | 14 +++++++++++ drivers/net/macvtap.c | 57 ++++++++++++++++++++++++++++++++++++++++++- drivers/net/tun.c | 59 ++++++++++++++++++++++++++++++++++++++++++++- include/uapi/linux/if_tun.h | 6 +++++ 4 files changed, 134 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index df51d6025a90..71ac0ece2d75 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -244,6 +244,20 @@ config TUN If you don't know what to use this for, you don't need it. +config TUN_VNET_CROSS_LE + bool "Support for cross-endian vnet headers on little-endian kernels" + default n + ---help--- + This option allows TUN/TAP and MACVTAP device drivers in a + little-endian kernel to parse vnet headers that come from a + big-endian legacy virtio device. + + Userspace programs can control the feature using the TUNSETVNETBE + and TUNGETVNETBE ioctls. + + Unless you have a little-endian system hosting a big-endian virtual + machine with a legacy virtio NIC, you should say N. + config VETH tristate "Virtual ethernet pair device" ---help--- diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 072ccbaf7c45..928f3f4db629 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -48,11 +48,60 @@ struct macvtap_queue { #define MACVTAP_FEATURES (IFF_VNET_HDR | IFF_MULTI_QUEUE) #define MACVTAP_VNET_LE 0x80000000 +#define MACVTAP_VNET_BE 0x40000000 + +#ifdef CONFIG_TUN_VNET_CROSS_LE +static inline bool macvtap_legacy_is_little_endian(struct macvtap_queue *q) +{ + return q->flags & MACVTAP_VNET_BE ? false : + virtio_legacy_is_little_endian(); +} + +static long macvtap_get_vnet_be(struct macvtap_queue *q, int __user *sp) +{ + int s = !!(q->flags & MACVTAP_VNET_BE); + + if (put_user(s, sp)) + return -EFAULT; + + return 0; +} + +static long macvtap_set_vnet_be(struct macvtap_queue *q, int __user *sp) +{ + int s; + + if (get_user(s, sp)) + return -EFAULT; + + if (s) + q->flags |= MACVTAP_VNET_BE; + else + q->flags &= ~MACVTAP_VNET_BE; + + return 0; +} +#else +static inline bool macvtap_legacy_is_little_endian(struct macvtap_queue *q) +{ + return virtio_legacy_is_little_endian(); +} + +static long macvtap_get_vnet_be(struct macvtap_queue *q, int __user *argp) +{ + return -EINVAL; +} + +static long macvtap_set_vnet_be(struct macvtap_queue *q, int __user *argp) +{ + return -EINVAL; +} +#endif /* CONFIG_TUN_VNET_CROSS_LE */ static inline bool macvtap_is_little_endian(struct macvtap_queue *q) { return q->flags & MACVTAP_VNET_LE || - virtio_legacy_is_little_endian(); + macvtap_legacy_is_little_endian(q); } static inline u16 macvtap16_to_cpu(struct macvtap_queue *q, __virtio16 val) @@ -1096,6 +1145,12 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd, q->flags &= ~MACVTAP_VNET_LE; return 0; + case TUNGETVNETBE: + return macvtap_get_vnet_be(q, sp); + + case TUNSETVNETBE: + return macvtap_set_vnet_be(q, sp); + case TUNSETOFFLOAD: /* let the user check for future flags */ if (arg & ~(TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 | diff --git a/drivers/net/tun.c b/drivers/net/tun.c index b210139bef8f..cb376b2d548a 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -111,6 +111,7 @@ do { \ #define TUN_FASYNC IFF_ATTACH_QUEUE /* High bits in flags field are unused. */ #define TUN_VNET_LE 0x80000000 +#define TUN_VNET_BE 0x40000000 #define TUN_FEATURES (IFF_NO_PI | IFF_ONE_QUEUE | IFF_VNET_HDR | \ IFF_MULTI_QUEUE) @@ -206,10 +207,58 @@ struct tun_struct { u32 flow_count; }; +#ifdef CONFIG_TUN_VNET_CROSS_LE +static inline bool tun_legacy_is_little_endian(struct tun_struct *tun) +{ + return tun->flags & TUN_VNET_BE ? false : + virtio_legacy_is_little_endian(); +} + +static long tun_get_vnet_be(struct tun_struct *tun, int __user *argp) +{ + int be = !!(tun->flags & TUN_VNET_BE); + + if (put_user(be, argp)) + return -EFAULT; + + return 0; +} + +static long tun_set_vnet_be(struct tun_struct *tun, int __user *argp) +{ + int be; + + if (get_user(be, argp)) + return -EFAULT; + + if (be) + tun->flags |= TUN_VNET_BE; + else + tun->flags &= ~TUN_VNET_BE; + + return 0; +} +#else +static inline bool tun_legacy_is_little_endian(struct tun_struct *tun) +{ + return virtio_legacy_is_little_endian(); +} + +static long tun_get_vnet_be(struct tun_struct *tun, int __user *argp) +{ + return -EINVAL; +} + +static long tun_set_vnet_be(struct tun_struct *tun, int __user *argp) +{ + return -EINVAL; +} +#endif /* CONFIG_TUN_VNET_CROSS_LE */ + static inline bool tun_is_little_endian(struct tun_struct *tun) { return tun->flags & TUN_VNET_LE || - virtio_legacy_is_little_endian(); + tun_legacy_is_little_endian(tun); } static inline u16 tun16_to_cpu(struct tun_struct *tun, __virtio16 val) @@ -2062,6 +2111,14 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, tun->flags &= ~TUN_VNET_LE; break; + case TUNGETVNETBE: + ret = tun_get_vnet_be(tun, argp); + break; + + case TUNSETVNETBE: + ret = tun_set_vnet_be(tun, argp); + break; + case TUNATTACHFILTER: /* Can be set only for TAPs */ ret = -EINVAL; diff --git a/include/uapi/linux/if_tun.h b/include/uapi/linux/if_tun.h index 50ae24335444..3cb5e1d85ddd 100644 --- a/include/uapi/linux/if_tun.h +++ b/include/uapi/linux/if_tun.h @@ -50,6 +50,12 @@ #define TUNGETFILTER _IOR('T', 219, struct sock_fprog) #define TUNSETVNETLE _IOW('T', 220, int) #define TUNGETVNETLE _IOR('T', 221, int) +/* The TUNSETVNETBE and TUNGETVNETBE ioctls are for cross-endian support on + * little-endian hosts. Not all kernel configurations support them, but all + * configurations that support SET also support GET. + */ +#define TUNSETVNETBE _IOW('T', 222, int) +#define TUNGETVNETBE _IOR('T', 223, int) /* TUNSETIFF ifr flags */ #define IFF_TUN 0x0001 -- cgit v1.2.3-70-g09d2 From 28a7eedd1109c9277390f44aa11de76b673996cd Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 1 Jun 2015 15:00:44 -0700 Subject: memory: omap-gpmc: Fix parsing of devices We currently artificially limit the parsing of GPMC connected devices based on the device name. Let's stop doing that, it's confusing as adding devices to .dts files with using normal names like fpga and usb will currently cause them to not probe. Cc: Roger Quadros Reported-by: Brian Hutchinson Signed-off-by: Tony Lindgren --- drivers/memory/omap-gpmc.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c index c94ea0d68746..0e524a1de56d 100644 --- a/drivers/memory/omap-gpmc.c +++ b/drivers/memory/omap-gpmc.c @@ -2074,14 +2074,8 @@ static int gpmc_probe_dt(struct platform_device *pdev) ret = gpmc_probe_nand_child(pdev, child); else if (of_node_cmp(child->name, "onenand") == 0) ret = gpmc_probe_onenand_child(pdev, child); - else if (of_node_cmp(child->name, "ethernet") == 0 || - of_node_cmp(child->name, "nor") == 0 || - of_node_cmp(child->name, "uart") == 0) + else ret = gpmc_probe_generic_child(pdev, child); - - if (WARN(ret < 0, "%s: probing gpmc child %s failed\n", - __func__, child->full_name)) - of_node_put(child); } return 0; -- cgit v1.2.3-70-g09d2 From ee83bd3b6483d59b0d4b509e46dae688d8e5759d Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Tue, 9 Jun 2015 23:35:00 -0700 Subject: serial: omap: Switch wake-up interrupt to generic wakeirq We can now use generic wakeirq handling and remove the custom handling for the wake-up interrupts. Acked-by: Greg Kroah-Hartman Signed-off-by: Tony Lindgren --- drivers/tty/serial/omap-serial.c | 35 ++++------------------------------- 1 file changed, 4 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 7f49172ccd86..7a2172b5e93c 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -160,7 +161,6 @@ struct uart_omap_port { unsigned long port_activity; int context_loss_cnt; u32 errata; - u8 wakeups_enabled; u32 features; int rts_gpio; @@ -209,28 +209,11 @@ static int serial_omap_get_context_loss_count(struct uart_omap_port *up) return pdata->get_context_loss_count(up->dev); } -static inline void serial_omap_enable_wakeirq(struct uart_omap_port *up, - bool enable) -{ - if (!up->wakeirq) - return; - - if (enable) - enable_irq(up->wakeirq); - else - disable_irq_nosync(up->wakeirq); -} - +/* REVISIT: Remove this when omap3 boots in device tree only mode */ static void serial_omap_enable_wakeup(struct uart_omap_port *up, bool enable) { struct omap_uart_port_info *pdata = dev_get_platdata(up->dev); - if (enable == up->wakeups_enabled) - return; - - serial_omap_enable_wakeirq(up, enable); - up->wakeups_enabled = enable; - if (!pdata || !pdata->enable_wakeup) return; @@ -750,13 +733,11 @@ static int serial_omap_startup(struct uart_port *port) /* Optional wake-up IRQ */ if (up->wakeirq) { - retval = request_irq(up->wakeirq, serial_omap_irq, - up->port.irqflags, up->name, up); + retval = dev_pm_set_dedicated_wake_irq(up->dev, up->wakeirq); if (retval) { free_irq(up->port.irq, up); return retval; } - disable_irq(up->wakeirq); } dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->port.line); @@ -845,8 +826,7 @@ static void serial_omap_shutdown(struct uart_port *port) pm_runtime_mark_last_busy(up->dev); pm_runtime_put_autosuspend(up->dev); free_irq(up->port.irq, up); - if (up->wakeirq) - free_irq(up->wakeirq, up); + dev_pm_clear_wake_irq(up->dev); } static void serial_omap_uart_qos_work(struct work_struct *work) @@ -1139,13 +1119,6 @@ serial_omap_pm(struct uart_port *port, unsigned int state, serial_out(up, UART_EFR, efr); serial_out(up, UART_LCR, 0); - if (!device_may_wakeup(up->dev)) { - if (!state) - pm_runtime_forbid(up->dev); - else - pm_runtime_allow(up->dev); - } - pm_runtime_mark_last_busy(up->dev); pm_runtime_put_autosuspend(up->dev); } -- cgit v1.2.3-70-g09d2 From a3e362f18c01f28abcb6d8e5d00be8b5d97ea09d Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Tue, 9 Jun 2015 23:35:00 -0700 Subject: serial: 8250_omap: Move wake-up interrupt to generic wakeirq We can now use generic wakeirq handling and remove the custom handling for the wake-up interrupts. Acked-by: Greg Kroah-Hartman Signed-off-by: Tony Lindgren --- drivers/tty/serial/8250/8250_omap.c | 58 +++---------------------------------- 1 file changed, 4 insertions(+), 54 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 978204333c94..d75a66c72750 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "8250.h" @@ -552,17 +553,6 @@ static void omap8250_uart_qos_work(struct work_struct *work) pm_qos_update_request(&priv->pm_qos_request, priv->latency); } -static irqreturn_t omap_wake_irq(int irq, void *dev_id) -{ - struct uart_port *port = dev_id; - int ret; - - ret = port->handle_irq(port); - if (ret) - return IRQ_HANDLED; - return IRQ_NONE; -} - #ifdef CONFIG_SERIAL_8250_DMA static int omap_8250_dma_handle_irq(struct uart_port *port); #endif @@ -596,11 +586,9 @@ static int omap_8250_startup(struct uart_port *port) int ret; if (priv->wakeirq) { - ret = request_irq(priv->wakeirq, omap_wake_irq, - port->irqflags, "uart wakeup irq", port); + ret = dev_pm_set_dedicated_wake_irq(port->dev, priv->wakeirq); if (ret) return ret; - disable_irq(priv->wakeirq); } pm_runtime_get_sync(port->dev); @@ -649,8 +637,7 @@ static int omap_8250_startup(struct uart_port *port) err: pm_runtime_mark_last_busy(port->dev); pm_runtime_put_autosuspend(port->dev); - if (priv->wakeirq) - free_irq(priv->wakeirq, port); + dev_pm_clear_wake_irq(port->dev); return ret; } @@ -682,10 +669,8 @@ static void omap_8250_shutdown(struct uart_port *port) pm_runtime_mark_last_busy(port->dev); pm_runtime_put_autosuspend(port->dev); - free_irq(port->irq, port); - if (priv->wakeirq) - free_irq(priv->wakeirq, port); + dev_pm_clear_wake_irq(port->dev); } static void omap_8250_throttle(struct uart_port *port) @@ -1226,31 +1211,6 @@ static int omap8250_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM - -static inline void omap8250_enable_wakeirq(struct omap8250_priv *priv, - bool enable) -{ - if (!priv->wakeirq) - return; - - if (enable) - enable_irq(priv->wakeirq); - else - disable_irq_nosync(priv->wakeirq); -} - -static void omap8250_enable_wakeup(struct omap8250_priv *priv, - bool enable) -{ - if (enable == priv->wakeups_enabled) - return; - - omap8250_enable_wakeirq(priv, enable); - priv->wakeups_enabled = enable; -} -#endif - #ifdef CONFIG_PM_SLEEP static int omap8250_prepare(struct device *dev) { @@ -1277,11 +1237,6 @@ static int omap8250_suspend(struct device *dev) serial8250_suspend_port(priv->line); flush_work(&priv->qos_work); - - if (device_may_wakeup(dev)) - omap8250_enable_wakeup(priv, true); - else - omap8250_enable_wakeup(priv, false); return 0; } @@ -1289,9 +1244,6 @@ static int omap8250_resume(struct device *dev) { struct omap8250_priv *priv = dev_get_drvdata(dev); - if (device_may_wakeup(dev)) - omap8250_enable_wakeup(priv, false); - serial8250_resume_port(priv->line); return 0; } @@ -1333,7 +1285,6 @@ static int omap8250_runtime_suspend(struct device *dev) return -EBUSY; } - omap8250_enable_wakeup(priv, true); if (up->dma) omap_8250_rx_dma(up, UART_IIR_RX_TIMEOUT); @@ -1354,7 +1305,6 @@ static int omap8250_runtime_resume(struct device *dev) return 0; up = serial8250_get_port(priv->line); - omap8250_enable_wakeup(priv, false); loss_cntx = omap8250_lost_context(up); if (loss_cntx) -- cgit v1.2.3-70-g09d2 From cc16d664e21ef640faaf51e9952384cf90b92d9f Mon Sep 17 00:00:00 2001 From: Wei Chen Date: Tue, 26 May 2015 08:28:29 +0000 Subject: hwspinlock: add a CSR atlas7 driver Add hwspinlock support for the CSR atlas7 SoC. The Hardware Spinlock device on atlas7 provides hardware assistance for synchronization between the multiple processors in the system (dual Cortex-A7, CAN bus Cortex-M3 and audio DSP). Reviewed-by: Suman Anna Reviewed-by: Bjorn Andersson Signed-off-by: Wei Chen Signed-off-by: Barry Song Signed-off-by: Ohad Ben-Cohen --- drivers/hwspinlock/Kconfig | 12 ++++ drivers/hwspinlock/Makefile | 1 + drivers/hwspinlock/sirf_hwspinlock.c | 136 +++++++++++++++++++++++++++++++++++ 3 files changed, 149 insertions(+) create mode 100644 drivers/hwspinlock/sirf_hwspinlock.c (limited to 'drivers') diff --git a/drivers/hwspinlock/Kconfig b/drivers/hwspinlock/Kconfig index b5b4f52cef73..73a401662853 100644 --- a/drivers/hwspinlock/Kconfig +++ b/drivers/hwspinlock/Kconfig @@ -30,6 +30,18 @@ config HWSPINLOCK_QCOM If unsure, say N. +config HWSPINLOCK_SIRF + tristate "SIRF Hardware Spinlock device" + depends on ARCH_SIRF + select HWSPINLOCK + help + Say y here to support the SIRF Hardware Spinlock device, which + provides a synchronisation mechanism for the various processors + on the SoC. + + It's safe to say n here if you're not interested in SIRF hardware + spinlock or just want a bare minimum kernel. + config HSEM_U8500 tristate "STE Hardware Semaphore functionality" depends on ARCH_U8500 diff --git a/drivers/hwspinlock/Makefile b/drivers/hwspinlock/Makefile index 68f95d9a4855..6b59cb5a4f3a 100644 --- a/drivers/hwspinlock/Makefile +++ b/drivers/hwspinlock/Makefile @@ -5,4 +5,5 @@ obj-$(CONFIG_HWSPINLOCK) += hwspinlock_core.o obj-$(CONFIG_HWSPINLOCK_OMAP) += omap_hwspinlock.o obj-$(CONFIG_HWSPINLOCK_QCOM) += qcom_hwspinlock.o +obj-$(CONFIG_HWSPINLOCK_SIRF) += sirf_hwspinlock.o obj-$(CONFIG_HSEM_U8500) += u8500_hsem.o diff --git a/drivers/hwspinlock/sirf_hwspinlock.c b/drivers/hwspinlock/sirf_hwspinlock.c new file mode 100644 index 000000000000..16018544d431 --- /dev/null +++ b/drivers/hwspinlock/sirf_hwspinlock.c @@ -0,0 +1,136 @@ +/* + * SIRF hardware spinlock driver + * + * Copyright (c) 2015 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hwspinlock_internal.h" + +struct sirf_hwspinlock { + void __iomem *io_base; + struct hwspinlock_device bank; +}; + +/* Number of Hardware Spinlocks*/ +#define HW_SPINLOCK_NUMBER 30 + +/* Hardware spinlock register offsets */ +#define HW_SPINLOCK_BASE 0x404 +#define HW_SPINLOCK_OFFSET(x) (HW_SPINLOCK_BASE + 0x4 * (x)) + +static int sirf_hwspinlock_trylock(struct hwspinlock *lock) +{ + void __iomem *lock_addr = lock->priv; + + /* attempt to acquire the lock by reading value == 1 from it */ + return !!readl(lock_addr); +} + +static void sirf_hwspinlock_unlock(struct hwspinlock *lock) +{ + void __iomem *lock_addr = lock->priv; + + /* release the lock by writing 0 to it */ + writel(0, lock_addr); +} + +static const struct hwspinlock_ops sirf_hwspinlock_ops = { + .trylock = sirf_hwspinlock_trylock, + .unlock = sirf_hwspinlock_unlock, +}; + +static int sirf_hwspinlock_probe(struct platform_device *pdev) +{ + struct sirf_hwspinlock *hwspin; + struct hwspinlock *hwlock; + int idx, ret; + + if (!pdev->dev.of_node) + return -ENODEV; + + hwspin = devm_kzalloc(&pdev->dev, sizeof(*hwspin) + + sizeof(*hwlock) * HW_SPINLOCK_NUMBER, GFP_KERNEL); + if (!hwspin) + return -ENOMEM; + + /* retrieve io base */ + hwspin->io_base = of_iomap(pdev->dev.of_node, 0); + if (!hwspin->io_base) + return -ENOMEM; + + for (idx = 0; idx < HW_SPINLOCK_NUMBER; idx++) { + hwlock = &hwspin->bank.lock[idx]; + hwlock->priv = hwspin->io_base + HW_SPINLOCK_OFFSET(idx); + } + + platform_set_drvdata(pdev, hwspin); + + pm_runtime_enable(&pdev->dev); + + ret = hwspin_lock_register(&hwspin->bank, &pdev->dev, + &sirf_hwspinlock_ops, 0, + HW_SPINLOCK_NUMBER); + if (ret) + goto reg_failed; + + return 0; + +reg_failed: + pm_runtime_disable(&pdev->dev); + iounmap(hwspin->io_base); + + return ret; +} + +static int sirf_hwspinlock_remove(struct platform_device *pdev) +{ + struct sirf_hwspinlock *hwspin = platform_get_drvdata(pdev); + int ret; + + ret = hwspin_lock_unregister(&hwspin->bank); + if (ret) { + dev_err(&pdev->dev, "%s failed: %d\n", __func__, ret); + return ret; + } + + pm_runtime_disable(&pdev->dev); + + iounmap(hwspin->io_base); + + return 0; +} + +static const struct of_device_id sirf_hwpinlock_ids[] = { + { .compatible = "sirf,hwspinlock", }, + {}, +}; +MODULE_DEVICE_TABLE(of, sirf_hwpinlock_ids); + +static struct platform_driver sirf_hwspinlock_driver = { + .probe = sirf_hwspinlock_probe, + .remove = sirf_hwspinlock_remove, + .driver = { + .name = "atlas7_hwspinlock", + .of_match_table = of_match_ptr(sirf_hwpinlock_ids), + }, +}; + +module_platform_driver(sirf_hwspinlock_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("SIRF Hardware spinlock driver"); +MODULE_AUTHOR("Wei Chen "); -- cgit v1.2.3-70-g09d2 From bc0c94b1404b225b19b6b53a0e508f43e269ed1e Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Wed, 20 May 2015 21:48:03 -0700 Subject: target: Drop unnecessary core_tpg_register TFO parameter This patch drops unnecessary target_core_fabric_ops parameter usage for core_tpg_register() during fabric driver TFO->fabric_make_tpg() se_portal_group creation callback execution. Instead, use the existing se_wwn->wwn_tf->tf_ops pointer to ensure fabric driver is really using the same TFO provided at module_init time. Also go ahead and drop the forward TFO declarations tree-wide, and handling the special case for iscsi-target discovery TPG. Cc: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Nicholas Bellinger --- drivers/infiniband/ulp/srpt/ib_srpt.c | 4 +--- drivers/scsi/qla2xxx/tcm_qla2xxx.c | 9 ++------- drivers/target/iscsi/iscsi_target_configfs.c | 3 +-- drivers/target/iscsi/iscsi_target_tpg.c | 8 ++++++-- drivers/target/loopback/tcm_loop.c | 5 +---- drivers/target/sbp/sbp_target.c | 2 +- drivers/target/target_core_tpg.c | 30 +++++++++++++++++++++++----- drivers/target/tcm_fc/tfc_conf.c | 5 +---- drivers/usb/gadget/legacy/tcm_usb_gadget.c | 5 +---- drivers/vhost/scsi.c | 4 +--- drivers/xen/xen-scsiback.c | 5 +---- include/target/target_core_fabric.h | 3 +-- 12 files changed, 42 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index dbad5c67a294..cea207e8b5d2 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -92,7 +92,6 @@ MODULE_PARM_DESC(srpt_service_guid, " instead of using the node_guid of the first HCA."); static struct ib_client srpt_client; -static const struct target_core_fabric_ops srpt_template; static void srpt_release_channel(struct srpt_rdma_ch *ch); static int srpt_queue_status(struct se_cmd *cmd); @@ -3733,8 +3732,7 @@ static struct se_portal_group *srpt_make_tpg(struct se_wwn *wwn, int res; /* Initialize sport->port_wwn and sport->port_tpg_1 */ - res = core_tpg_register(&srpt_template, &sport->port_wwn, - &sport->port_tpg_1, SCSI_PROTOCOL_SRP); + res = core_tpg_register(&sport->port_wwn, &sport->port_tpg_1, SCSI_PROTOCOL_SRP); if (res) return ERR_PTR(res); diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index cb53144c72d0..e14a7fd7d810 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -52,9 +52,6 @@ static struct workqueue_struct *tcm_qla2xxx_free_wq; static struct workqueue_struct *tcm_qla2xxx_cmd_wq; -static const struct target_core_fabric_ops tcm_qla2xxx_ops; -static const struct target_core_fabric_ops tcm_qla2xxx_npiv_ops; - /* * Parse WWN. * If strict, we require lower-case hex and colon separators to be sure @@ -1004,8 +1001,7 @@ static struct se_portal_group *tcm_qla2xxx_make_tpg( tpg->tpg_attrib.cache_dynamic_acls = 1; tpg->tpg_attrib.demo_mode_login_only = 1; - ret = core_tpg_register(&tcm_qla2xxx_ops, wwn, &tpg->se_tpg, - SCSI_PROTOCOL_FCP); + ret = core_tpg_register(wwn, &tpg->se_tpg, SCSI_PROTOCOL_FCP); if (ret < 0) { kfree(tpg); return NULL; @@ -1124,8 +1120,7 @@ static struct se_portal_group *tcm_qla2xxx_npiv_make_tpg( tpg->tpg_attrib.cache_dynamic_acls = 1; tpg->tpg_attrib.demo_mode_login_only = 1; - ret = core_tpg_register(&tcm_qla2xxx_npiv_ops, wwn, &tpg->se_tpg, - SCSI_PROTOCOL_FCP); + ret = core_tpg_register(wwn, &tpg->se_tpg, SCSI_PROTOCOL_FCP); if (ret < 0) { kfree(tpg); return NULL; diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 523ae556e22c..c1898c84b3d2 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -1419,8 +1419,7 @@ static struct se_portal_group *lio_target_tiqn_addtpg( if (!tpg) return NULL; - ret = core_tpg_register(&iscsi_ops, wwn, &tpg->tpg_se_tpg, - SCSI_PROTOCOL_ISCSI); + ret = core_tpg_register(wwn, &tpg->tpg_se_tpg, SCSI_PROTOCOL_ISCSI); if (ret < 0) return NULL; diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c index de8829102ab4..968068ffcb1c 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.c +++ b/drivers/target/iscsi/iscsi_target_tpg.c @@ -66,8 +66,12 @@ int iscsit_load_discovery_tpg(void) pr_err("Unable to allocate struct iscsi_portal_group\n"); return -1; } - - ret = core_tpg_register(&iscsi_ops, NULL, &tpg->tpg_se_tpg, -1); + /* + * Save iscsi_ops pointer for special case discovery TPG that + * doesn't exist as se_wwn->wwn_group within configfs. + */ + tpg->tpg_se_tpg.se_tpg_tfo = &iscsi_ops; + ret = core_tpg_register(NULL, &tpg->tpg_se_tpg, -1); if (ret < 0) { kfree(tpg); return -1; diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index b0c17614493e..bd9d11a6f823 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -40,8 +40,6 @@ #define to_tcm_loop_hba(hba) container_of(hba, struct tcm_loop_hba, dev) -static const struct target_core_fabric_ops loop_ops; - static struct workqueue_struct *tcm_loop_workqueue; static struct kmem_cache *tcm_loop_cmd_cache; @@ -1081,8 +1079,7 @@ static struct se_portal_group *tcm_loop_make_naa_tpg( /* * Register the tl_tpg as a emulated SAS TCM Target Endpoint */ - ret = core_tpg_register(&loop_ops, wwn, &tl_tpg->tl_se_tpg, - tl_hba->tl_proto_id); + ret = core_tpg_register(wwn, &tl_tpg->tl_se_tpg, tl_hba->tl_proto_id); if (ret < 0) return ERR_PTR(-ENOMEM); diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index 28e3adf1eb85..42f82d32ca85 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -2055,7 +2055,7 @@ static struct se_portal_group *sbp_make_tpg( goto out_free_tpg; } - ret = core_tpg_register(&sbp_ops, wwn, &tpg->se_tpg, SCSI_PROTOCOL_SBP); + ret = core_tpg_register(wwn, &tpg->se_tpg, SCSI_PROTOCOL_SBP); if (ret < 0) goto out_unreg_mgt_agt; diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index b9fcf2c4898e..2e77eebe1671 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -37,6 +37,7 @@ #include #include +#include #include #include "target_core_internal.h" @@ -487,16 +488,34 @@ static void core_tpg_lun_ref_release(struct percpu_ref *ref) } int core_tpg_register( - const struct target_core_fabric_ops *tfo, struct se_wwn *se_wwn, struct se_portal_group *se_tpg, int proto_id) { int ret; + if (!se_tpg) + return -EINVAL; + /* + * For the typical case where core_tpg_register() is called by a + * fabric driver from target_core_fabric_ops->fabric_make_tpg() + * configfs context, use the original tf_ops pointer already saved + * by target-core in target_fabric_make_wwn(). + * + * Otherwise, for special cases like iscsi-target discovery TPGs + * the caller is responsible for setting ->se_tpg_tfo ahead of + * calling core_tpg_register(). + */ + if (se_wwn) + se_tpg->se_tpg_tfo = se_wwn->wwn_tf->tf_ops; + + if (!se_tpg->se_tpg_tfo) { + pr_err("Unable to locate se_tpg->se_tpg_tfo pointer\n"); + return -EINVAL; + } + INIT_HLIST_HEAD(&se_tpg->tpg_lun_hlist); se_tpg->proto_id = proto_id; - se_tpg->se_tpg_tfo = tfo; se_tpg->se_tpg_wwn = se_wwn; atomic_set(&se_tpg->tpg_pr_ref_count, 0); INIT_LIST_HEAD(&se_tpg->acl_node_list); @@ -524,9 +543,10 @@ int core_tpg_register( spin_unlock_bh(&tpg_lock); pr_debug("TARGET_CORE[%s]: Allocated portal_group for endpoint: %s, " - "Proto: %d, Portal Tag: %u\n", tfo->get_fabric_name(), - tfo->tpg_get_wwn(se_tpg) ? tfo->tpg_get_wwn(se_tpg) : NULL, - se_tpg->proto_id, tfo->tpg_get_tag(se_tpg)); + "Proto: %d, Portal Tag: %u\n", se_tpg->se_tpg_tfo->get_fabric_name(), + se_tpg->se_tpg_tfo->tpg_get_wwn(se_tpg) ? + se_tpg->se_tpg_tfo->tpg_get_wwn(se_tpg) : NULL, + se_tpg->proto_id, se_tpg->se_tpg_tfo->tpg_get_tag(se_tpg)); return 0; } diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c index 8e1a54f2642c..80a4477fa7ee 100644 --- a/drivers/target/tcm_fc/tfc_conf.c +++ b/drivers/target/tcm_fc/tfc_conf.c @@ -47,8 +47,6 @@ #include "tcm_fc.h" -static const struct target_core_fabric_ops ft_fabric_ops; - static LIST_HEAD(ft_wwn_list); DEFINE_MUTEX(ft_lport_lock); @@ -282,8 +280,7 @@ static struct se_portal_group *ft_add_tpg( return NULL; } - ret = core_tpg_register(&ft_fabric_ops, wwn, &tpg->se_tpg, - SCSI_PROTOCOL_FCP); + ret = core_tpg_register(wwn, &tpg->se_tpg, SCSI_PROTOCOL_FCP); if (ret < 0) { destroy_workqueue(wq); kfree(tpg); diff --git a/drivers/usb/gadget/legacy/tcm_usb_gadget.c b/drivers/usb/gadget/legacy/tcm_usb_gadget.c index 16b9a16678fe..4ff426edf22a 100644 --- a/drivers/usb/gadget/legacy/tcm_usb_gadget.c +++ b/drivers/usb/gadget/legacy/tcm_usb_gadget.c @@ -28,8 +28,6 @@ USB_GADGET_COMPOSITE_OPTIONS(); -static const struct target_core_fabric_ops usbg_ops; - static inline struct f_uas *to_f_uas(struct usb_function *f) { return container_of(f, struct f_uas, function); @@ -1418,8 +1416,7 @@ static struct se_portal_group *usbg_make_tpg( * SPC doesn't assign a protocol identifier for USB-SCSI, so we * pretend to be SAS.. */ - ret = core_tpg_register(&usbg_ops, wwn, &tpg->se_tpg, - SCSI_PROTOCOL_SAS); + ret = core_tpg_register(wwn, &tpg->se_tpg, SCSI_PROTOCOL_SAS); if (ret < 0) { destroy_workqueue(tpg->workqueue); kfree(tpg); diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index dcd228b59ded..450aece0227c 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -206,7 +206,6 @@ struct vhost_scsi { int vs_events_nr; /* num of pending events, protected by vq->mutex */ }; -static struct target_core_fabric_ops vhost_scsi_ops; static struct workqueue_struct *vhost_scsi_workqueue; /* Global spinlock to protect vhost_scsi TPG list for vhost IOCTL access */ @@ -2001,8 +2000,7 @@ vhost_scsi_make_tpg(struct se_wwn *wwn, tpg->tport = tport; tpg->tport_tpgt = tpgt; - ret = core_tpg_register(&vhost_scsi_ops, wwn, &tpg->se_tpg, - tport->tport_proto_id); + ret = core_tpg_register(wwn, &tpg->se_tpg, tport->tport_proto_id); if (ret < 0) { kfree(tpg); return NULL; diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index 555033bd9239..25144a0ff07c 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -203,8 +203,6 @@ static LIST_HEAD(scsiback_free_pages); static DEFINE_MUTEX(scsiback_mutex); static LIST_HEAD(scsiback_list); -static const struct target_core_fabric_ops scsiback_ops; - static void scsiback_get(struct vscsibk_info *info) { atomic_inc(&info->nr_unreplied_reqs); @@ -1765,8 +1763,7 @@ scsiback_make_tpg(struct se_wwn *wwn, tpg->tport = tport; tpg->tport_tpgt = tpgt; - ret = core_tpg_register(&scsiback_ops, wwn, &tpg->se_tpg, - tport->tport_proto_id); + ret = core_tpg_register(wwn, &tpg->se_tpg, tport->tport_proto_id); if (ret < 0) { kfree(tpg); return NULL; diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index b1e00a7d66de..d6216b761333 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -161,8 +161,7 @@ int core_tpg_set_initiator_node_queue_depth(struct se_portal_group *, unsigned char *, u32, int); int core_tpg_set_initiator_node_tag(struct se_portal_group *, struct se_node_acl *, const char *); -int core_tpg_register(const struct target_core_fabric_ops *, - struct se_wwn *, struct se_portal_group *, int); +int core_tpg_register(struct se_wwn *, struct se_portal_group *, int); int core_tpg_deregister(struct se_portal_group *); /* -- cgit v1.2.3-70-g09d2 From e34d366273ce17bba902975f7c1e64a24a399024 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Sun, 31 May 2015 22:14:03 -0700 Subject: target: Drop duplicate + unused se_dev_check_wce Reported-by: kbuild test robot Reported-by: Bart Van Assche Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_device.c | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 3baa6cd7fded..db531fb5e787 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -538,18 +538,6 @@ static u32 se_dev_align_max_sectors(u32 max_sectors, u32 block_size) return aligned_max_sectors; } -bool se_dev_check_wce(struct se_device *dev) -{ - bool wce = false; - - if (dev->transport->get_write_cache) - wce = dev->transport->get_write_cache(dev); - else if (dev->dev_attrib.emulate_write_cache > 0) - wce = true; - - return wce; -} - int core_dev_add_lun( struct se_portal_group *tpg, struct se_device *dev, -- cgit v1.2.3-70-g09d2 From f2d30680204f20b815e6796437923fb870b6c193 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Wed, 10 Jun 2015 08:41:22 +0200 Subject: target: use 64-bit LUNs As we're now using a list to hold the LUNs the target core can now converted to use 64-bit LUNs internally. Signed-off-by: Hannes Reinecke Signed-off-by: Nicholas Bellinger --- drivers/target/iscsi/iscsi_target_tmr.c | 4 +-- drivers/target/loopback/tcm_loop.c | 4 +-- drivers/target/target_core_alua.c | 2 +- drivers/target/target_core_configfs.c | 12 ++++---- drivers/target/target_core_device.c | 30 +++++++++---------- drivers/target/target_core_fabric_configfs.c | 18 ++++-------- drivers/target/target_core_internal.h | 10 +++---- drivers/target/target_core_pr.c | 43 ++++++++++++++-------------- drivers/target/target_core_pr.h | 6 ++-- drivers/target/target_core_tpg.c | 6 ++-- drivers/target/target_core_transport.c | 6 ++-- drivers/target/target_core_ua.c | 8 +++--- drivers/target/target_core_ua.h | 2 +- include/target/target_core_base.h | 19 ++++++------ include/target/target_core_fabric.h | 10 +++---- 15 files changed, 88 insertions(+), 92 deletions(-) (limited to 'drivers') diff --git a/drivers/target/iscsi/iscsi_target_tmr.c b/drivers/target/iscsi/iscsi_target_tmr.c index b0224a77e26d..515988258e9e 100644 --- a/drivers/target/iscsi/iscsi_target_tmr.c +++ b/drivers/target/iscsi/iscsi_target_tmr.c @@ -120,7 +120,7 @@ u8 iscsit_tmr_task_reassign( struct iscsi_tmr_req *tmr_req = cmd->tmr_req; struct se_tmr_req *se_tmr = cmd->se_cmd.se_tmr_req; struct iscsi_tm *hdr = (struct iscsi_tm *) buf; - int ret, ref_lun; + u64 ret, ref_lun; pr_debug("Got TASK_REASSIGN TMR ITT: 0x%08x," " RefTaskTag: 0x%08x, ExpDataSN: 0x%08x, CID: %hu\n", @@ -164,7 +164,7 @@ u8 iscsit_tmr_task_reassign( ref_lun = scsilun_to_int(&hdr->lun); if (ref_lun != ref_cmd->se_cmd.orig_fe_lun) { pr_err("Unable to perform connection recovery for" - " differing ref_lun: %d ref_cmd orig_fe_lun: %u\n", + " differing ref_lun: %llu ref_cmd orig_fe_lun: %llu\n", ref_lun, ref_cmd->se_cmd.orig_fe_lun); return ISCSI_TMF_RSP_REJECTED; } diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index bd9d11a6f823..a556bdebd775 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -215,7 +215,7 @@ static int tcm_loop_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *sc) * to struct scsi_device */ static int tcm_loop_issue_tmr(struct tcm_loop_tpg *tl_tpg, - int lun, int task, enum tcm_tmreq_table tmr) + u64 lun, int task, enum tcm_tmreq_table tmr) { struct se_cmd *se_cmd = NULL; struct se_session *se_sess; @@ -747,7 +747,7 @@ static void tcm_loop_port_unlink( se_lun->unpacked_lun); if (!sd) { pr_err("Unable to locate struct scsi_device for %d:%d:" - "%d\n", 0, tl_tpg->tl_tpgt, se_lun->unpacked_lun); + "%llu\n", 0, tl_tpg->tl_tpgt, se_lun->unpacked_lun); return; } /* diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 02d8e1a8a6a5..2318e6e5ce52 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -1257,7 +1257,7 @@ static int core_alua_update_tpg_secondary_metadata(struct se_lun *lun) atomic_read(&lun->lun_tg_pt_secondary_offline), lun->lun_tg_pt_secondary_stat); - snprintf(path, ALUA_METADATA_PATH_LEN, "/var/target/alua/%s/%s/lun_%u", + snprintf(path, ALUA_METADATA_PATH_LEN, "/var/target/alua/%s/%s/lun_%llu", se_tpg->se_tpg_tfo->get_fabric_name(), wwn, lun->unpacked_lun); diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index f97b969e6714..68addbc7eb7b 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -1438,7 +1438,7 @@ static ssize_t target_core_dev_pr_show_attr_res_pr_holder_tg_port( tfo->tpg_get_wwn(se_tpg)); len += sprintf(page+len, "SPC-3 Reservation: Relative Port" " Identifier Tag: %hu %s Portal Group Tag: %hu" - " %s Logical Unit: %u\n", pr_reg->tg_pt_sep_rtpi, + " %s Logical Unit: %llu\n", pr_reg->tg_pt_sep_rtpi, tfo->get_fabric_name(), tfo->tpg_get_tag(se_tpg), tfo->get_fabric_name(), pr_reg->pr_aptpl_target_lun); @@ -1565,12 +1565,12 @@ static match_table_t tokens = { {Opt_res_type, "res_type=%d"}, {Opt_res_scope, "res_scope=%d"}, {Opt_res_all_tg_pt, "res_all_tg_pt=%d"}, - {Opt_mapped_lun, "mapped_lun=%d"}, + {Opt_mapped_lun, "mapped_lun=%lld"}, {Opt_target_fabric, "target_fabric=%s"}, {Opt_target_node, "target_node=%s"}, {Opt_tpgt, "tpgt=%d"}, {Opt_port_rtpi, "port_rtpi=%d"}, - {Opt_target_lun, "target_lun=%d"}, + {Opt_target_lun, "target_lun=%lld"}, {Opt_err, NULL} }; @@ -1585,7 +1585,7 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( substring_t args[MAX_OPT_ARGS]; unsigned long long tmp_ll; u64 sa_res_key = 0; - u32 mapped_lun = 0, target_lun = 0; + u64 mapped_lun = 0, target_lun = 0; int ret = -1, res_holder = 0, all_tg_pt = 0, arg, token; u16 tpgt = 0; u8 type = 0; @@ -1675,7 +1675,7 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( break; case Opt_mapped_lun: match_int(args, &arg); - mapped_lun = (u32)arg; + mapped_lun = (u64)arg; break; /* * PR APTPL Metadata for Target Port @@ -1710,7 +1710,7 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( break; case Opt_target_lun: match_int(args, &arg); - target_lun = (u32)arg; + target_lun = (u64)arg; break; default: break; diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index db531fb5e787..2ea7322c4dd4 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -56,7 +56,7 @@ static struct se_hba *lun0_hba; struct se_device *g_lun0_dev; sense_reason_t -transport_lookup_cmd_lun(struct se_cmd *se_cmd, u32 unpacked_lun) +transport_lookup_cmd_lun(struct se_cmd *se_cmd, u64 unpacked_lun) { struct se_lun *se_lun = NULL; struct se_session *se_sess = se_cmd->se_sess; @@ -74,7 +74,7 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd, u32 unpacked_lun) if ((se_cmd->data_direction == DMA_TO_DEVICE) && (deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY)) { pr_err("TARGET_CORE[%s]: Detected WRITE_PROTECTED LUN" - " Access for 0x%08x\n", + " Access for 0x%08llx\n", se_cmd->se_tfo->get_fabric_name(), unpacked_lun); rcu_read_unlock(); @@ -107,7 +107,7 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd, u32 unpacked_lun) */ if (unpacked_lun != 0) { pr_err("TARGET_CORE[%s]: Detected NON_EXISTENT_LUN" - " Access for 0x%08x\n", + " Access for 0x%08llx\n", se_cmd->se_tfo->get_fabric_name(), unpacked_lun); return TCM_NON_EXISTENT_LUN; @@ -147,7 +147,7 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd, u32 unpacked_lun) } EXPORT_SYMBOL(transport_lookup_cmd_lun); -int transport_lookup_tmr_lun(struct se_cmd *se_cmd, u32 unpacked_lun) +int transport_lookup_tmr_lun(struct se_cmd *se_cmd, u64 unpacked_lun) { struct se_dev_entry *deve; struct se_lun *se_lun = NULL; @@ -172,7 +172,7 @@ int transport_lookup_tmr_lun(struct se_cmd *se_cmd, u32 unpacked_lun) if (!se_lun) { pr_debug("TARGET_CORE[%s]: Detected NON_EXISTENT_LUN" - " Access for 0x%08x\n", + " Access for 0x%08llx\n", se_cmd->se_tfo->get_fabric_name(), unpacked_lun); return -ENODEV; @@ -260,7 +260,7 @@ void core_free_device_list_for_node( } void core_update_device_list_access( - u32 mapped_lun, + u64 mapped_lun, u32 lun_access, struct se_node_acl *nacl) { @@ -283,7 +283,7 @@ void core_update_device_list_access( /* * Called with rcu_read_lock or nacl->device_list_lock held. */ -struct se_dev_entry *target_nacl_find_deve(struct se_node_acl *nacl, u32 mapped_lun) +struct se_dev_entry *target_nacl_find_deve(struct se_node_acl *nacl, u64 mapped_lun) { struct se_dev_entry *deve; @@ -309,7 +309,7 @@ void target_pr_kref_release(struct kref *kref) int core_enable_device_list_for_node( struct se_lun *lun, struct se_lun_acl *lun_acl, - u32 mapped_lun, + u64 mapped_lun, u32 lun_access, struct se_node_acl *nacl, struct se_portal_group *tpg) @@ -550,7 +550,7 @@ int core_dev_add_lun( if (rc < 0) return rc; - pr_debug("%s_TPG[%u]_LUN[%u] - Activated %s Logical Unit from" + pr_debug("%s_TPG[%u]_LUN[%llu] - Activated %s Logical Unit from" " CORE HBA: %u\n", tpg->se_tpg_tfo->get_fabric_name(), tpg->se_tpg_tfo->tpg_get_tag(tpg), lun->unpacked_lun, tpg->se_tpg_tfo->get_fabric_name(), dev->se_hba->hba_id); @@ -583,7 +583,7 @@ void core_dev_del_lun( struct se_portal_group *tpg, struct se_lun *lun) { - pr_debug("%s_TPG[%u]_LUN[%u] - Deactivating %s Logical Unit from" + pr_debug("%s_TPG[%u]_LUN[%llu] - Deactivating %s Logical Unit from" " device object\n", tpg->se_tpg_tfo->get_fabric_name(), tpg->se_tpg_tfo->tpg_get_tag(tpg), lun->unpacked_lun, tpg->se_tpg_tfo->get_fabric_name()); @@ -594,7 +594,7 @@ void core_dev_del_lun( struct se_lun_acl *core_dev_init_initiator_node_lun_acl( struct se_portal_group *tpg, struct se_node_acl *nacl, - u32 mapped_lun, + u64 mapped_lun, int *ret) { struct se_lun_acl *lacl; @@ -646,7 +646,7 @@ int core_dev_add_initiator_node_lun_acl( lun_access, nacl, tpg) < 0) return -EINVAL; - pr_debug("%s_TPG[%hu]_LUN[%u->%u] - Added %s ACL for " + pr_debug("%s_TPG[%hu]_LUN[%llu->%llu] - Added %s ACL for " " InitiatorNode: %s\n", tpg->se_tpg_tfo->get_fabric_name(), tpg->se_tpg_tfo->tpg_get_tag(tpg), lun->unpacked_lun, lacl->mapped_lun, (lun_access & TRANSPORT_LUNFLAGS_READ_WRITE) ? "RW" : "RO", @@ -678,8 +678,8 @@ int core_dev_del_initiator_node_lun_acl( core_disable_device_list_for_node(lun, deve, nacl, tpg); mutex_unlock(&nacl->lun_entry_mutex); - pr_debug("%s_TPG[%hu]_LUN[%u] - Removed ACL for" - " InitiatorNode: %s Mapped LUN: %u\n", + pr_debug("%s_TPG[%hu]_LUN[%llu] - Removed ACL for" + " InitiatorNode: %s Mapped LUN: %llu\n", tpg->se_tpg_tfo->get_fabric_name(), tpg->se_tpg_tfo->tpg_get_tag(tpg), lun->unpacked_lun, lacl->initiatorname, lacl->mapped_lun); @@ -692,7 +692,7 @@ void core_dev_free_initiator_node_lun_acl( struct se_lun_acl *lacl) { pr_debug("%s_TPG[%hu] - Freeing ACL for %s InitiatorNode: %s" - " Mapped LUN: %u\n", tpg->se_tpg_tfo->get_fabric_name(), + " Mapped LUN: %llu\n", tpg->se_tpg_tfo->get_fabric_name(), tpg->se_tpg_tfo->tpg_get_tag(tpg), tpg->se_tpg_tfo->get_fabric_name(), lacl->initiatorname, lacl->mapped_lun); diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index 0ee182fce1a6..2fd493e416b0 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -202,7 +202,7 @@ static ssize_t target_fabric_mappedlun_store_write_protect( lacl->se_lun_nacl); pr_debug("%s_ConfigFS: Changed Initiator ACL: %s" - " Mapped LUN: %u Write Protect bit to %s\n", + " Mapped LUN: %llu Write Protect bit to %s\n", se_tpg->se_tpg_tfo->get_fabric_name(), lacl->initiatorname, lacl->mapped_lun, (op) ? "ON" : "OFF"); @@ -322,7 +322,7 @@ static struct config_group *target_fabric_make_mappedlun( struct config_item *acl_ci; struct config_group *lacl_cg = NULL, *ml_stat_grp = NULL; char *buf; - unsigned long mapped_lun; + unsigned long long mapped_lun; int ret = 0; acl_ci = &group->cg_item; @@ -350,15 +350,11 @@ static struct config_group *target_fabric_make_mappedlun( * Determine the Mapped LUN value. This is what the SCSI Initiator * Port will actually see. */ - ret = kstrtoul(buf + 4, 0, &mapped_lun); + ret = kstrtoull(buf + 4, 0, &mapped_lun); if (ret) goto out; - if (mapped_lun > UINT_MAX) { - ret = -EINVAL; - goto out; - } if (mapped_lun > (TRANSPORT_MAX_LUNS_PER_TPG-1)) { - pr_err("Mapped LUN: %lu exceeds TRANSPORT_MAX_LUNS_PER_TPG" + pr_err("Mapped LUN: %llu exceeds TRANSPORT_MAX_LUNS_PER_TPG" "-1: %u for Target Portal Group: %u\n", mapped_lun, TRANSPORT_MAX_LUNS_PER_TPG-1, se_tpg->se_tpg_tfo->tpg_get_tag(se_tpg)); @@ -881,7 +877,7 @@ static struct config_group *target_fabric_make_lun( struct se_portal_group, tpg_lun_group); struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; struct config_group *lun_cg = NULL, *port_stat_grp = NULL; - unsigned long unpacked_lun; + unsigned long long unpacked_lun; int errno; if (strstr(name, "lun_") != name) { @@ -889,11 +885,9 @@ static struct config_group *target_fabric_make_lun( " \"lun_$LUN_NUMBER\"\n"); return ERR_PTR(-EINVAL); } - errno = kstrtoul(name + 4, 0, &unpacked_lun); + errno = kstrtoull(name + 4, 0, &unpacked_lun); if (errno) return ERR_PTR(errno); - if (unpacked_lun > UINT_MAX) - return ERR_PTR(-EINVAL); lun = core_tpg_alloc_lun(se_tpg, unpacked_lun); if (IS_ERR(lun)) diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index 8d8737a13e6f..511178969df3 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -26,10 +26,10 @@ struct se_dev_entry *core_get_se_deve_from_rtpi(struct se_node_acl *, u16); void target_pr_kref_release(struct kref *); void core_free_device_list_for_node(struct se_node_acl *, struct se_portal_group *); -void core_update_device_list_access(u32, u32, struct se_node_acl *); -struct se_dev_entry *target_nacl_find_deve(struct se_node_acl *, u32); +void core_update_device_list_access(u64, u32, struct se_node_acl *); +struct se_dev_entry *target_nacl_find_deve(struct se_node_acl *, u64); int core_enable_device_list_for_node(struct se_lun *, struct se_lun_acl *, - u32, u32, struct se_node_acl *, struct se_portal_group *); + u64, u32, struct se_node_acl *, struct se_portal_group *); void core_disable_device_list_for_node(struct se_lun *, struct se_dev_entry *, struct se_node_acl *, struct se_portal_group *); void core_clear_lun_from_tpg(struct se_lun *, struct se_portal_group *); @@ -37,7 +37,7 @@ int core_dev_add_lun(struct se_portal_group *, struct se_device *, struct se_lun *lun); void core_dev_del_lun(struct se_portal_group *, struct se_lun *); struct se_lun_acl *core_dev_init_initiator_node_lun_acl(struct se_portal_group *, - struct se_node_acl *, u32, int *); + struct se_node_acl *, u64, int *); int core_dev_add_initiator_node_lun_acl(struct se_portal_group *, struct se_lun_acl *, struct se_lun *lun, u32); int core_dev_del_initiator_node_lun_acl(struct se_lun *, @@ -80,7 +80,7 @@ struct se_node_acl *__core_tpg_get_initiator_node_acl(struct se_portal_group *tp void core_tpg_add_node_to_devs(struct se_node_acl *, struct se_portal_group *, struct se_lun *); void core_tpg_wait_for_nacl_pr_ref(struct se_node_acl *); -struct se_lun *core_tpg_alloc_lun(struct se_portal_group *, u32); +struct se_lun *core_tpg_alloc_lun(struct se_portal_group *, u64); int core_tpg_add_lun(struct se_portal_group *, struct se_lun *, u32, struct se_device *); void core_tpg_remove_lun(struct se_portal_group *, struct se_lun *); diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 94935eaa7fa7..436e30b14a11 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -229,8 +229,9 @@ target_scsi2_reservation_release(struct se_cmd *cmd) dev->dev_reservation_flags &= ~DRF_SPC2_RESERVATIONS_WITH_ISID; } tpg = sess->se_tpg; - pr_debug("SCSI-2 Released reservation for %s LUN: %u ->" - " MAPPED LUN: %u for %s\n", tpg->se_tpg_tfo->get_fabric_name(), + pr_debug("SCSI-2 Released reservation for %s LUN: %llu ->" + " MAPPED LUN: %llu for %s\n", + tpg->se_tpg_tfo->get_fabric_name(), cmd->se_lun->unpacked_lun, cmd->orig_fe_lun, sess->se_node_acl->initiatorname); @@ -275,10 +276,10 @@ target_scsi2_reservation_reserve(struct se_cmd *cmd) (dev->dev_reserved_node_acl != sess->se_node_acl)) { pr_err("SCSI-2 RESERVATION CONFLIFT for %s fabric\n", tpg->se_tpg_tfo->get_fabric_name()); - pr_err("Original reserver LUN: %u %s\n", + pr_err("Original reserver LUN: %llu %s\n", cmd->se_lun->unpacked_lun, dev->dev_reserved_node_acl->initiatorname); - pr_err("Current attempt - LUN: %u -> MAPPED LUN: %u" + pr_err("Current attempt - LUN: %llu -> MAPPED LUN: %llu" " from %s \n", cmd->se_lun->unpacked_lun, cmd->orig_fe_lun, sess->se_node_acl->initiatorname); @@ -292,7 +293,7 @@ target_scsi2_reservation_reserve(struct se_cmd *cmd) dev->dev_res_bin_isid = sess->sess_bin_isid; dev->dev_reservation_flags |= DRF_SPC2_RESERVATIONS_WITH_ISID; } - pr_debug("SCSI-2 Reserved %s LUN: %u -> MAPPED LUN: %u" + pr_debug("SCSI-2 Reserved %s LUN: %llu -> MAPPED LUN: %llu" " for %s\n", tpg->se_tpg_tfo->get_fabric_name(), cmd->se_lun->unpacked_lun, cmd->orig_fe_lun, sess->se_node_acl->initiatorname); @@ -618,7 +619,7 @@ static struct t10_pr_registration *__core_scsi3_do_alloc_registration( struct se_node_acl *nacl, struct se_lun *lun, struct se_dev_entry *deve, - u32 mapped_lun, + u64 mapped_lun, unsigned char *isid, u64 sa_res_key, int all_tg_pt, @@ -671,7 +672,7 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( struct se_node_acl *nacl, struct se_lun *lun, struct se_dev_entry *deve, - u32 mapped_lun, + u64 mapped_lun, unsigned char *isid, u64 sa_res_key, int all_tg_pt, @@ -804,10 +805,10 @@ int core_scsi3_alloc_aptpl_registration( u64 sa_res_key, unsigned char *i_port, unsigned char *isid, - u32 mapped_lun, + u64 mapped_lun, unsigned char *t_port, u16 tpgt, - u32 target_lun, + u64 target_lun, int res_holder, int all_tg_pt, u8 type) @@ -901,9 +902,9 @@ static int __core_scsi3_check_aptpl_registration( struct se_device *dev, struct se_portal_group *tpg, struct se_lun *lun, - u32 target_lun, + u64 target_lun, struct se_node_acl *nacl, - u32 mapped_lun) + u64 mapped_lun) { struct t10_pr_registration *pr_reg, *pr_reg_tmp; struct t10_reservation *pr_tmpl = &dev->t10_pr; @@ -972,7 +973,7 @@ int core_scsi3_check_aptpl_registration( struct se_portal_group *tpg, struct se_lun *lun, struct se_node_acl *nacl, - u32 mapped_lun) + u64 mapped_lun) { if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS) return 0; @@ -1094,7 +1095,7 @@ static int core_scsi3_alloc_registration( struct se_node_acl *nacl, struct se_lun *lun, struct se_dev_entry *deve, - u32 mapped_lun, + u64 mapped_lun, unsigned char *isid, u64 sa_res_key, int all_tg_pt, @@ -1668,7 +1669,7 @@ core_scsi3_decode_spec_i_port( } pr_debug("SPC-3 PR SPEC_I_PT: Located %s Node: %s" - " dest_se_deve mapped_lun: %u\n", + " dest_se_deve mapped_lun: %llu\n", dest_tpg->se_tpg_tfo->get_fabric_name(), dest_node_acl->initiatorname, dest_se_deve->mapped_lun); @@ -1780,7 +1781,7 @@ core_scsi3_decode_spec_i_port( pr_debug("SPC-3 PR [%s] SPEC_I_PT: Successfully" " registered Transport ID for Node: %s%s Mapped LUN:" - " %u\n", dest_tpg->se_tpg_tfo->get_fabric_name(), + " %llu\n", dest_tpg->se_tpg_tfo->get_fabric_name(), dest_node_acl->initiatorname, i_buf, (dest_se_deve) ? dest_se_deve->mapped_lun : 0); @@ -1873,7 +1874,7 @@ static int core_scsi3_update_aptpl_buf( "sa_res_key=%llu\n" "res_holder=1\nres_type=%02x\n" "res_scope=%02x\nres_all_tg_pt=%d\n" - "mapped_lun=%u\n", reg_count, + "mapped_lun=%llu\n", reg_count, tpg->se_tpg_tfo->get_fabric_name(), pr_reg->pr_reg_nacl->initiatorname, isid_buf, pr_reg->pr_res_key, pr_reg->pr_res_type, @@ -1883,7 +1884,7 @@ static int core_scsi3_update_aptpl_buf( snprintf(tmp, 512, "PR_REG_START: %d\n" "initiator_fabric=%s\ninitiator_node=%s\n%s" "sa_res_key=%llu\nres_holder=0\n" - "res_all_tg_pt=%d\nmapped_lun=%u\n", + "res_all_tg_pt=%d\nmapped_lun=%llu\n", reg_count, tpg->se_tpg_tfo->get_fabric_name(), pr_reg->pr_reg_nacl->initiatorname, isid_buf, pr_reg->pr_res_key, pr_reg->pr_reg_all_tg_pt, @@ -1902,7 +1903,7 @@ static int core_scsi3_update_aptpl_buf( * Include information about the associated SCSI target port. */ snprintf(tmp, 512, "target_fabric=%s\ntarget_node=%s\n" - "tpgt=%hu\nport_rtpi=%hu\ntarget_lun=%u\nPR_REG_END:" + "tpgt=%hu\nport_rtpi=%hu\ntarget_lun=%llu\nPR_REG_END:" " %d\n", tpg->se_tpg_tfo->get_fabric_name(), tpg->se_tpg_tfo->tpg_get_wwn(tpg), tpg->se_tpg_tfo->tpg_get_tag(tpg), @@ -2646,7 +2647,7 @@ core_scsi3_emulate_pro_clear(struct se_cmd *cmd, u64 res_key) struct se_session *se_sess = cmd->se_sess; struct t10_reservation *pr_tmpl = &dev->t10_pr; struct t10_pr_registration *pr_reg, *pr_reg_tmp, *pr_reg_n, *pr_res_holder; - u32 pr_res_mapped_lun = 0; + u64 pr_res_mapped_lun = 0; int calling_it_nexus = 0; /* * Locate the existing *pr_reg via struct se_node_acl pointers @@ -2802,7 +2803,7 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key, LIST_HEAD(preempt_and_abort_list); struct t10_pr_registration *pr_reg, *pr_reg_tmp, *pr_reg_n, *pr_res_holder; struct t10_reservation *pr_tmpl = &dev->t10_pr; - u32 pr_res_mapped_lun = 0; + u64 pr_res_mapped_lun = 0; int all_reg = 0, calling_it_nexus = 0; bool sa_res_key_unmatched = sa_res_key != 0; int prh_type = 0, prh_scope = 0; @@ -3350,7 +3351,7 @@ after_iport_check: } pr_debug("SPC-3 PR REGISTER_AND_MOVE: Located %s node %s LUN" - " ACL for dest_se_deve->mapped_lun: %u\n", + " ACL for dest_se_deve->mapped_lun: %llu\n", dest_tf_ops->get_fabric_name(), dest_node_acl->initiatorname, dest_se_deve->mapped_lun); diff --git a/drivers/target/target_core_pr.h b/drivers/target/target_core_pr.h index 749fd7bb7510..e3d26e9126a0 100644 --- a/drivers/target/target_core_pr.h +++ b/drivers/target/target_core_pr.h @@ -56,11 +56,11 @@ extern sense_reason_t target_scsi2_reservation_release(struct se_cmd *); extern sense_reason_t target_scsi2_reservation_reserve(struct se_cmd *); extern int core_scsi3_alloc_aptpl_registration( struct t10_reservation *, u64, - unsigned char *, unsigned char *, u32, - unsigned char *, u16, u32, int, int, u8); + unsigned char *, unsigned char *, u64, + unsigned char *, u16, u64, int, int, u8); extern int core_scsi3_check_aptpl_registration(struct se_device *, struct se_portal_group *, struct se_lun *, - struct se_node_acl *, u32); + struct se_node_acl *, u64); extern void core_scsi3_free_pr_reg_from_nacl(struct se_device *, struct se_node_acl *); extern void core_scsi3_free_all_registrations(struct se_device *); diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index 2e77eebe1671..82ed8a0f3f0e 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -122,7 +122,7 @@ void core_tpg_add_node_to_devs( lun_access = TRANSPORT_LUNFLAGS_READ_WRITE; } - pr_debug("TARGET_CORE[%s]->TPG[%u]_LUN[%u] - Adding %s" + pr_debug("TARGET_CORE[%s]->TPG[%u]_LUN[%llu] - Adding %s" " access for LUN in Demo Mode\n", tpg->se_tpg_tfo->get_fabric_name(), tpg->se_tpg_tfo->tpg_get_tag(tpg), lun->unpacked_lun, @@ -598,12 +598,12 @@ EXPORT_SYMBOL(core_tpg_deregister); struct se_lun *core_tpg_alloc_lun( struct se_portal_group *tpg, - u32 unpacked_lun) + u64 unpacked_lun) { struct se_lun *lun; if (unpacked_lun > (TRANSPORT_MAX_LUNS_PER_TPG-1)) { - pr_err("%s LUN: %u exceeds TRANSPORT_MAX_LUNS_PER_TPG" + pr_err("%s LUN: %llu exceeds TRANSPORT_MAX_LUNS_PER_TPG" "-1: %u for Target Portal Group: %u\n", tpg->se_tpg_tfo->get_fabric_name(), unpacked_lun, TRANSPORT_MAX_LUNS_PER_TPG-1, diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index d8a59122fe3b..eed9580b7f6c 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1366,7 +1366,7 @@ transport_generic_map_mem_to_cmd(struct se_cmd *cmd, struct scatterlist *sgl, * assumes internal allocation of fabric payload buffer by target-core. */ int target_submit_cmd_map_sgls(struct se_cmd *se_cmd, struct se_session *se_sess, - unsigned char *cdb, unsigned char *sense, u32 unpacked_lun, + unsigned char *cdb, unsigned char *sense, u64 unpacked_lun, u32 data_length, int task_attr, int data_dir, int flags, struct scatterlist *sgl, u32 sgl_count, struct scatterlist *sgl_bidi, u32 sgl_bidi_count, @@ -1502,7 +1502,7 @@ EXPORT_SYMBOL(target_submit_cmd_map_sgls); * It also assumes interal target core SGL memory allocation. */ int target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, - unsigned char *cdb, unsigned char *sense, u32 unpacked_lun, + unsigned char *cdb, unsigned char *sense, u64 unpacked_lun, u32 data_length, int task_attr, int data_dir, int flags) { return target_submit_cmd_map_sgls(se_cmd, se_sess, cdb, sense, @@ -1539,7 +1539,7 @@ static void target_complete_tmr_failure(struct work_struct *work) **/ int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess, - unsigned char *sense, u32 unpacked_lun, + unsigned char *sense, u64 unpacked_lun, void *fabric_tmr_ptr, unsigned char tm_type, gfp_t gfp, unsigned int tag, int flags) { diff --git a/drivers/target/target_core_ua.c b/drivers/target/target_core_ua.c index 6c9616d212b1..e53d4eec2ebc 100644 --- a/drivers/target/target_core_ua.c +++ b/drivers/target/target_core_ua.c @@ -88,7 +88,7 @@ target_scsi3_ua_check(struct se_cmd *cmd) int core_scsi3_ua_allocate( struct se_node_acl *nacl, - u32 unpacked_lun, + u64 unpacked_lun, u8 asc, u8 ascq) { @@ -177,7 +177,7 @@ int core_scsi3_ua_allocate( list_add_tail(&ua->ua_nacl_list, &deve->ua_list); spin_unlock(&deve->ua_lock); - pr_debug("[%s]: Allocated UNIT ATTENTION, mapped LUN: %u, ASC:" + pr_debug("[%s]: Allocated UNIT ATTENTION, mapped LUN: %llu, ASC:" " 0x%02x, ASCQ: 0x%02x\n", nacl->se_tpg->se_tpg_tfo->get_fabric_name(), unpacked_lun, asc, ascq); @@ -267,7 +267,7 @@ void core_scsi3_ua_for_check_condition( rcu_read_unlock(); pr_debug("[%s]: %s UNIT ATTENTION condition with" - " INTLCK_CTRL: %d, mapped LUN: %u, got CDB: 0x%02x" + " INTLCK_CTRL: %d, mapped LUN: %llu, got CDB: 0x%02x" " reported ASC: 0x%02x, ASCQ: 0x%02x\n", nacl->se_tpg->se_tpg_tfo->get_fabric_name(), (dev->dev_attrib.emulate_ua_intlck_ctrl != 0) ? "Reporting" : @@ -329,7 +329,7 @@ int core_scsi3_ua_clear_for_request_sense( rcu_read_unlock(); pr_debug("[%s]: Released UNIT ATTENTION condition, mapped" - " LUN: %u, got REQUEST_SENSE reported ASC: 0x%02x," + " LUN: %llu, got REQUEST_SENSE reported ASC: 0x%02x," " ASCQ: 0x%02x\n", nacl->se_tpg->se_tpg_tfo->get_fabric_name(), cmd->orig_fe_lun, *asc, *ascq); diff --git a/drivers/target/target_core_ua.h b/drivers/target/target_core_ua.h index a6b56b364e7a..6e592b10a8c0 100644 --- a/drivers/target/target_core_ua.h +++ b/drivers/target/target_core_ua.h @@ -28,7 +28,7 @@ extern struct kmem_cache *se_ua_cache; extern sense_reason_t target_scsi3_ua_check(struct se_cmd *); -extern int core_scsi3_ua_allocate(struct se_node_acl *, u32, u8, u8); +extern int core_scsi3_ua_allocate(struct se_node_acl *, u64, u8, u8); extern void core_scsi3_ua_release_all(struct se_dev_entry *); extern void core_scsi3_ua_for_check_condition(struct se_cmd *, u8 *, u8 *); extern int core_scsi3_ua_clear_for_request_sense(struct se_cmd *, diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index eefc2b0cfaa3..836ff8abdf18 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -355,8 +355,8 @@ struct t10_pr_registration { int pr_res_scope; /* Used for fabric initiator WWPNs using a ISID */ bool isid_present_at_reg; - u32 pr_res_mapped_lun; - u32 pr_aptpl_target_lun; + u64 pr_res_mapped_lun; + u64 pr_aptpl_target_lun; u16 tg_pt_sep_rtpi; u32 pr_res_generation; u64 pr_reg_bin_isid; @@ -476,7 +476,7 @@ struct se_cmd { /* Total size in bytes associated with command */ u32 data_length; u32 residual_count; - u32 orig_fe_lun; + u64 orig_fe_lun; /* Persistent Reservation key */ u64 pr_res_key; /* Used for sense data */ @@ -614,7 +614,7 @@ struct se_ml_stat_grps { struct se_lun_acl { char initiatorname[TRANSPORT_IQN_LEN]; - u32 mapped_lun; + u64 mapped_lun; struct se_node_acl *se_lun_nacl; struct se_lun *se_lun; struct config_group se_lun_group; @@ -623,10 +623,10 @@ struct se_lun_acl { struct se_dev_entry { /* See transport_lunflags_table */ - u32 lun_flags; - u32 mapped_lun; + u64 mapped_lun; u64 pr_res_key; u64 creation_time; + u32 lun_flags; u32 attach_count; atomic_long_t total_cmds; atomic_long_t read_bytes; @@ -696,14 +696,15 @@ struct scsi_port_stats { }; struct se_lun { - /* RELATIVE TARGET PORT IDENTIFER */ - u16 lun_rtpi; + u64 unpacked_lun; #define SE_LUN_LINK_MAGIC 0xffff7771 u32 lun_link_magic; u32 lun_access; u32 lun_flags; - u32 unpacked_lun; u32 lun_index; + + /* RELATIVE TARGET PORT IDENTIFER */ + u16 lun_rtpi; atomic_t lun_acl_count; struct se_device __rcu *lun_se_dev; diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index d6216b761333..18afef91b447 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -116,16 +116,16 @@ void transport_deregister_session(struct se_session *); void transport_init_se_cmd(struct se_cmd *, const struct target_core_fabric_ops *, struct se_session *, u32, int, int, unsigned char *); -sense_reason_t transport_lookup_cmd_lun(struct se_cmd *, u32); +sense_reason_t transport_lookup_cmd_lun(struct se_cmd *, u64); sense_reason_t target_setup_cmd_from_cdb(struct se_cmd *, unsigned char *); int target_submit_cmd_map_sgls(struct se_cmd *, struct se_session *, - unsigned char *, unsigned char *, u32, u32, int, int, int, + unsigned char *, unsigned char *, u64, u32, int, int, int, struct scatterlist *, u32, struct scatterlist *, u32, struct scatterlist *, u32); int target_submit_cmd(struct se_cmd *, struct se_session *, unsigned char *, - unsigned char *, u32, u32, int, int, int); + unsigned char *, u64, u32, int, int, int); int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess, - unsigned char *sense, u32 unpacked_lun, + unsigned char *sense, u64 unpacked_lun, void *fabric_tmr_ptr, unsigned char tm_type, gfp_t, unsigned int, int); int transport_handle_cdb_direct(struct se_cmd *); @@ -151,7 +151,7 @@ void core_tmr_release_req(struct se_tmr_req *); int transport_generic_handle_tmr(struct se_cmd *); void transport_generic_request_failure(struct se_cmd *, sense_reason_t); void __target_execute_cmd(struct se_cmd *); -int transport_lookup_tmr_lun(struct se_cmd *, u32); +int transport_lookup_tmr_lun(struct se_cmd *, u64); struct se_node_acl *core_tpg_get_initiator_node_acl(struct se_portal_group *tpg, unsigned char *); -- cgit v1.2.3-70-g09d2 From 196e2e2aa362850bf45bcb14b9517124b23b921e Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Wed, 10 Jun 2015 08:41:23 +0200 Subject: target: Remove TARGET_MAX_LUNS_PER_TRANSPORT LUN allocation is now fully dynamic, so there is no need to artificially restrain the number of exported LUNs. Signed-off-by: Hannes Reinecke Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_device.c | 9 --------- drivers/target/target_core_fabric_configfs.c | 8 -------- drivers/target/target_core_tpg.c | 9 --------- drivers/xen/xen-scsiback.c | 7 ++++--- include/target/target_core_base.h | 3 --- 5 files changed, 4 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 2ea7322c4dd4..ed084023e7d4 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -63,9 +63,6 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd, u64 unpacked_lun) struct se_node_acl *nacl = se_sess->se_node_acl; struct se_dev_entry *deve; - if (unpacked_lun >= TRANSPORT_MAX_LUNS_PER_TPG) - return TCM_NON_EXISTENT_LUN; - rcu_read_lock(); deve = target_nacl_find_deve(nacl, unpacked_lun); if (deve) { @@ -156,9 +153,6 @@ int transport_lookup_tmr_lun(struct se_cmd *se_cmd, u64 unpacked_lun) struct se_tmr_req *se_tmr = se_cmd->se_tmr_req; unsigned long flags; - if (unpacked_lun >= TRANSPORT_MAX_LUNS_PER_TPG) - return -ENODEV; - rcu_read_lock(); deve = target_nacl_find_deve(nacl, unpacked_lun); if (deve) { @@ -197,9 +191,6 @@ bool target_lun_is_rdonly(struct se_cmd *cmd) struct se_dev_entry *deve; bool ret; - if (cmd->se_lun->lun_access & TRANSPORT_LUNFLAGS_READ_ONLY) - return true; - rcu_read_lock(); deve = target_nacl_find_deve(se_sess->se_node_acl, cmd->orig_fe_lun); ret = (deve && deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY); diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index 2fd493e416b0..6cfee595f3f2 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -353,14 +353,6 @@ static struct config_group *target_fabric_make_mappedlun( ret = kstrtoull(buf + 4, 0, &mapped_lun); if (ret) goto out; - if (mapped_lun > (TRANSPORT_MAX_LUNS_PER_TPG-1)) { - pr_err("Mapped LUN: %llu exceeds TRANSPORT_MAX_LUNS_PER_TPG" - "-1: %u for Target Portal Group: %u\n", mapped_lun, - TRANSPORT_MAX_LUNS_PER_TPG-1, - se_tpg->se_tpg_tfo->tpg_get_tag(se_tpg)); - ret = -EINVAL; - goto out; - } lacl = core_dev_init_initiator_node_lun_acl(se_tpg, se_nacl, mapped_lun, &ret); diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index 82ed8a0f3f0e..aa39bc89227b 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -602,15 +602,6 @@ struct se_lun *core_tpg_alloc_lun( { struct se_lun *lun; - if (unpacked_lun > (TRANSPORT_MAX_LUNS_PER_TPG-1)) { - pr_err("%s LUN: %llu exceeds TRANSPORT_MAX_LUNS_PER_TPG" - "-1: %u for Target Portal Group: %u\n", - tpg->se_tpg_tfo->get_fabric_name(), - unpacked_lun, TRANSPORT_MAX_LUNS_PER_TPG-1, - tpg->se_tpg_tfo->tpg_get_tag(tpg)); - return ERR_PTR(-EOVERFLOW); - } - lun = kzalloc(sizeof(*lun), GFP_KERNEL); if (!lun) { pr_err("Unable to allocate se_lun memory\n"); diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index 25144a0ff07c..10d67802a2fb 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -864,7 +864,7 @@ static int scsiback_add_translation_entry(struct vscsibk_info *info, struct list_head *head = &(info->v2p_entry_lists); unsigned long flags; char *lunp; - unsigned int unpacked_lun; + unsigned long long unpacked_lun; struct se_lun *se_lun; struct scsiback_tpg *tpg_entry, *tpg = NULL; char *error = "doesn't exist"; @@ -876,9 +876,10 @@ static int scsiback_add_translation_entry(struct vscsibk_info *info, } *lunp = 0; lunp++; - if (kstrtouint(lunp, 10, &unpacked_lun) || unpacked_lun >= TRANSPORT_MAX_LUNS_PER_TPG) { + err = kstrtoull(lunp, 10, &unpacked_lun); + if (err < 0) { pr_err("lun number not valid: %s\n", lunp); - return -EINVAL; + return err; } mutex_lock(&scsiback_mutex); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 836ff8abdf18..8cb612613c10 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -13,9 +13,6 @@ #define TARGET_CORE_MOD_VERSION "v4.1.0" #define TARGET_CORE_VERSION TARGET_CORE_MOD_VERSION -/* Maximum Number of LUNs per Target Portal Group */ -/* Don't raise above 511 or REPORT_LUNS needs to handle >1 page */ -#define TRANSPORT_MAX_LUNS_PER_TPG 256 /* * By default we use 32-byte CDBs in TCM Core and subsystem plugin code. * -- cgit v1.2.3-70-g09d2 From 0fb1f14e88f6f814fc578d0b8b3de666d1c9327e Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Tue, 16 Jun 2015 00:37:16 -0700 Subject: xen-scsiback: Fix compile warning for 64-bit LUN MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/xen/xen-scsiback.c: In function ‘scsiback_add_translation_entry’: drivers/xen/xen-scsiback.c:911:3: warning: format ‘%d’ expects argument of type ‘int’, but argument 3 has type ‘long long unsigned int’ [-Wformat] Signed-off-by: Nicholas Bellinger --- drivers/xen/xen-scsiback.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index 10d67802a2fb..823bdf4cc36e 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -908,7 +908,7 @@ static int scsiback_add_translation_entry(struct vscsibk_info *info, mutex_unlock(&scsiback_mutex); if (!tpg) { - pr_err("%s:%d %s\n", phy, unpacked_lun, error); + pr_err("%s:%llu %s\n", phy, unpacked_lun, error); return -ENODEV; } -- cgit v1.2.3-70-g09d2 From ee8c07d0c32622b6fa44108b0141434575e43188 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 11 Jun 2015 10:01:24 +0200 Subject: target_core_alua: Correct UA handling when switching states When switching target port group ALUA states we need to send one UA when setting the ALUA state to 'transitioning', and another one once the final state has been set. Signed-off-by: Hannes Reinecke Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_alua.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 2318e6e5ce52..228a3c7925e5 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -941,16 +941,11 @@ static int core_alua_update_tpg_primary_metadata( return rc; } -static void core_alua_do_transition_tg_pt_work(struct work_struct *work) +static void core_alua_queue_state_change_ua(struct t10_alua_tg_pt_gp *tg_pt_gp) { - struct t10_alua_tg_pt_gp *tg_pt_gp = container_of(work, - struct t10_alua_tg_pt_gp, tg_pt_gp_transition_work.work); - struct se_device *dev = tg_pt_gp->tg_pt_gp_dev; struct se_dev_entry *se_deve; struct se_lun *lun; struct se_lun_acl *lacl; - bool explicit = (tg_pt_gp->tg_pt_gp_alua_access_status == - ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG); spin_lock(&tg_pt_gp->tg_pt_gp_lock); list_for_each_entry(lun, &tg_pt_gp->tg_pt_gp_lun_list, @@ -1002,6 +997,16 @@ static void core_alua_do_transition_tg_pt_work(struct work_struct *work) percpu_ref_put(&lun->lun_ref); } spin_unlock(&tg_pt_gp->tg_pt_gp_lock); +} + +static void core_alua_do_transition_tg_pt_work(struct work_struct *work) +{ + struct t10_alua_tg_pt_gp *tg_pt_gp = container_of(work, + struct t10_alua_tg_pt_gp, tg_pt_gp_transition_work.work); + struct se_device *dev = tg_pt_gp->tg_pt_gp_dev; + bool explicit = (tg_pt_gp->tg_pt_gp_alua_access_status == + ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG); + /* * Update the ALUA metadata buf that has been allocated in * core_alua_do_port_transition(), this metadata will be written @@ -1031,6 +1036,9 @@ static void core_alua_do_transition_tg_pt_work(struct work_struct *work) tg_pt_gp->tg_pt_gp_id, core_alua_dump_state(tg_pt_gp->tg_pt_gp_alua_previous_state), core_alua_dump_state(tg_pt_gp->tg_pt_gp_alua_pending_state)); + + core_alua_queue_state_change_ua(tg_pt_gp); + spin_lock(&dev->t10_alua.tg_pt_gps_lock); atomic_dec(&tg_pt_gp->tg_pt_gp_ref_cnt); spin_unlock(&dev->t10_alua.tg_pt_gps_lock); @@ -1083,6 +1091,8 @@ static int core_alua_do_transition_tg_pt( ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG : ALUA_STATUS_ALTERED_BY_IMPLICIT_ALUA; + core_alua_queue_state_change_ua(tg_pt_gp); + /* * Check for the optional ALUA primary state transition delay */ -- cgit v1.2.3-70-g09d2 From 316058134ffa0017199b460318e109aa79432cc6 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 11 Jun 2015 10:01:25 +0200 Subject: target: Remove 'ua_nacl' pointer from se_ua structure Unused. Signed-off-by: Hannes Reinecke Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_ua.c | 1 - include/target/target_core_base.h | 1 - 2 files changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_ua.c b/drivers/target/target_core_ua.c index e53d4eec2ebc..e5062245171e 100644 --- a/drivers/target/target_core_ua.c +++ b/drivers/target/target_core_ua.c @@ -107,7 +107,6 @@ int core_scsi3_ua_allocate( } INIT_LIST_HEAD(&ua->ua_nacl_list); - ua->ua_nacl = nacl; ua->ua_asc = asc; ua->ua_ascq = ascq; diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 8cb612613c10..8a4f861f12b7 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -548,7 +548,6 @@ struct se_cmd { struct se_ua { u8 ua_asc; u8 ua_ascq; - struct se_node_acl *ua_nacl; struct list_head ua_nacl_list; }; -- cgit v1.2.3-70-g09d2 From fec47d863587c272d6fbf4e50066209c953d5e60 Mon Sep 17 00:00:00 2001 From: Dave Gerlach Date: Fri, 22 May 2015 15:45:27 -0500 Subject: remoteproc: introduce rproc_get_by_phandle API Allow users of remoteproc the ability to get a handle to an rproc by passing a phandle supplied in the user's device tree node. This is useful in situations that require manual booting of the rproc. This patch uses the code removed by commit 40e575b1d0b3 ("remoteproc: remove the get_by_name/put API") for the ref counting but is modified to use a simple list and locking mechanism and has rproc_get_by_name replaced with an rproc_get_by_phandle API. Signed-off-by: Dave Gerlach Signed-off-by: Suman Anna [fix order of Signed-off-by tags] Signed-off-by: Ohad Ben-Cohen --- Documentation/remoteproc.txt | 6 +++++ drivers/remoteproc/remoteproc_core.c | 50 ++++++++++++++++++++++++++++++++++++ include/linux/remoteproc.h | 7 ++--- 3 files changed, 60 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/Documentation/remoteproc.txt b/Documentation/remoteproc.txt index e6469fdcf89a..ef0219fa4bb4 100644 --- a/Documentation/remoteproc.txt +++ b/Documentation/remoteproc.txt @@ -51,6 +51,12 @@ cost. rproc_shutdown() returns, and users can still use it with a subsequent rproc_boot(), if needed. + struct rproc *rproc_get_by_phandle(phandle phandle) + - Find an rproc handle using a device tree phandle. Returns the rproc + handle on success, and NULL on failure. This function increments + the remote processor's refcount, so always use rproc_put() to + decrement it back once rproc isn't needed anymore. + 3. Typical usage #include diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index e991512e04ed..e1a6d693b8bb 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -44,6 +44,9 @@ #include "remoteproc_internal.h" +static DEFINE_MUTEX(rproc_list_mutex); +static LIST_HEAD(rproc_list); + typedef int (*rproc_handle_resources_t)(struct rproc *rproc, struct resource_table *table, int len); typedef int (*rproc_handle_resource_t)(struct rproc *rproc, @@ -1144,6 +1147,43 @@ out: } EXPORT_SYMBOL(rproc_shutdown); +/** + * rproc_get_by_phandle() - find a remote processor by phandle + * @phandle: phandle to the rproc + * + * Finds an rproc handle using the remote processor's phandle, and then + * return a handle to the rproc. + * + * This function increments the remote processor's refcount, so always + * use rproc_put() to decrement it back once rproc isn't needed anymore. + * + * Returns the rproc handle on success, and NULL on failure. + */ +struct rproc *rproc_get_by_phandle(phandle phandle) +{ + struct rproc *rproc = NULL, *r; + struct device_node *np; + + np = of_find_node_by_phandle(phandle); + if (!np) + return NULL; + + mutex_lock(&rproc_list_mutex); + list_for_each_entry(r, &rproc_list, node) { + if (r->dev.parent && r->dev.parent->of_node == np) { + rproc = r; + get_device(&rproc->dev); + break; + } + } + mutex_unlock(&rproc_list_mutex); + + of_node_put(np); + + return rproc; +} +EXPORT_SYMBOL(rproc_get_by_phandle); + /** * rproc_add() - register a remote processor * @rproc: the remote processor handle to register @@ -1173,6 +1213,11 @@ int rproc_add(struct rproc *rproc) if (ret < 0) return ret; + /* expose to rproc_get_by_phandle users */ + mutex_lock(&rproc_list_mutex); + list_add(&rproc->node, &rproc_list); + mutex_unlock(&rproc_list_mutex); + dev_info(dev, "%s is available\n", rproc->name); dev_info(dev, "Note: remoteproc is still under development and considered experimental.\n"); @@ -1360,6 +1405,11 @@ int rproc_del(struct rproc *rproc) /* Free the copy of the resource table */ kfree(rproc->cached_table); + /* the rproc is downref'ed as soon as it's removed from the klist */ + mutex_lock(&rproc_list_mutex); + list_del(&rproc->node); + mutex_unlock(&rproc_list_mutex); + device_del(&rproc->dev); return 0; diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h index 78b8a9b9d40a..56739e5df1e6 100644 --- a/include/linux/remoteproc.h +++ b/include/linux/remoteproc.h @@ -36,11 +36,11 @@ #define REMOTEPROC_H #include -#include #include #include #include #include +#include /** * struct resource_table - firmware resource table header @@ -375,7 +375,7 @@ enum rproc_crash_type { /** * struct rproc - represents a physical remote processor device - * @node: klist node of this rproc object + * @node: list node of this rproc object * @domain: iommu domain * @name: human readable name of the rproc * @firmware: name of firmware file to be loaded @@ -407,7 +407,7 @@ enum rproc_crash_type { * @has_iommu: flag to indicate if remote processor is behind an MMU */ struct rproc { - struct klist_node node; + struct list_head node; struct iommu_domain *domain; const char *name; const char *firmware; @@ -481,6 +481,7 @@ struct rproc_vdev { u32 rsc_offset; }; +struct rproc *rproc_get_by_phandle(phandle phandle); struct rproc *rproc_alloc(struct device *dev, const char *name, const struct rproc_ops *ops, const char *firmware, int len); -- cgit v1.2.3-70-g09d2 From c51c8e7bcac966f209da83630fc8ca7e6cad279b Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 11 Jun 2015 10:01:26 +0200 Subject: target: use 'se_dev_entry' when allocating UAs We need to use 'se_dev_entry' as argument when allocating UAs, otherwise we'll never see any UAs for an implicit ALUA state transition triggered from userspace. (Add target_ua_allocate_lun() common caller - nab) Signed-off-by: Hannes Reinecke Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_alua.c | 27 ++++++++++++++-------- drivers/target/target_core_pr.c | 12 +++++----- drivers/target/target_core_transport.c | 12 +++++----- drivers/target/target_core_ua.c | 42 ++++++++++++++++++---------------- drivers/target/target_core_ua.h | 3 ++- 5 files changed, 54 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 228a3c7925e5..aa2e4b103d43 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -972,23 +972,32 @@ static void core_alua_queue_state_change_ua(struct t10_alua_tg_pt_gp *tg_pt_gp) list_for_each_entry(se_deve, &lun->lun_deve_list, lun_link) { lacl = rcu_dereference_check(se_deve->se_lun_acl, lockdep_is_held(&lun->lun_deve_lock)); + /* - * se_deve->se_lun_acl pointer may be NULL for a - * entry created without explicit Node+MappedLUN ACLs + * spc4r37 p.242: + * After an explicit target port asymmetric access + * state change, a device server shall establish a + * unit attention condition with the additional sense + * code set to ASYMMETRIC ACCESS STATE CHANGED for + * the initiator port associated with every I_T nexus + * other than the I_T nexus on which the SET TARGET + * PORT GROUPS command was received. */ - if (!lacl) - continue; - if ((tg_pt_gp->tg_pt_gp_alua_access_status == ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG) && - (tg_pt_gp->tg_pt_gp_alua_nacl != NULL) && - (tg_pt_gp->tg_pt_gp_alua_nacl == lacl->se_lun_nacl) && (tg_pt_gp->tg_pt_gp_alua_lun != NULL) && (tg_pt_gp->tg_pt_gp_alua_lun == lun)) continue; - core_scsi3_ua_allocate(lacl->se_lun_nacl, - se_deve->mapped_lun, 0x2A, + /* + * se_deve->se_lun_acl pointer may be NULL for a + * entry created without explicit Node+MappedLUN ACLs + */ + if (lacl && (tg_pt_gp->tg_pt_gp_alua_nacl != NULL) && + (tg_pt_gp->tg_pt_gp_alua_nacl == lacl->se_lun_nacl)) + continue; + + core_scsi3_ua_allocate(se_deve, 0x2A, ASCQ_2AH_ASYMMETRIC_ACCESS_STATE_CHANGED); } spin_unlock_bh(&lun->lun_deve_lock); diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 436e30b14a11..0bb329243dba 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -2197,7 +2197,7 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key, &pr_tmpl->registration_list, pr_reg_list) { - core_scsi3_ua_allocate( + target_ua_allocate_lun( pr_reg_p->pr_reg_nacl, pr_reg_p->pr_res_mapped_lun, 0x2A, @@ -2624,7 +2624,7 @@ core_scsi3_emulate_pro_release(struct se_cmd *cmd, int type, int scope, if (pr_reg_p == pr_reg) continue; - core_scsi3_ua_allocate(pr_reg_p->pr_reg_nacl, + target_ua_allocate_lun(pr_reg_p->pr_reg_nacl, pr_reg_p->pr_res_mapped_lun, 0x2A, ASCQ_2AH_RESERVATIONS_RELEASED); } @@ -2709,7 +2709,7 @@ core_scsi3_emulate_pro_clear(struct se_cmd *cmd, u64 res_key) * additional sense code set to RESERVATIONS PREEMPTED. */ if (!calling_it_nexus) - core_scsi3_ua_allocate(pr_reg_nacl, pr_res_mapped_lun, + target_ua_allocate_lun(pr_reg_nacl, pr_res_mapped_lun, 0x2A, ASCQ_2AH_RESERVATIONS_PREEMPTED); } spin_unlock(&pr_tmpl->registration_lock); @@ -2918,7 +2918,7 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key, NULL, 0); } if (!calling_it_nexus) - core_scsi3_ua_allocate(pr_reg_nacl, + target_ua_allocate_lun(pr_reg_nacl, pr_res_mapped_lun, 0x2A, ASCQ_2AH_REGISTRATIONS_PREEMPTED); } @@ -3024,7 +3024,7 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key, * persistent reservation and/or registration, with the * additional sense code set to REGISTRATIONS PREEMPTED; */ - core_scsi3_ua_allocate(pr_reg_nacl, pr_res_mapped_lun, 0x2A, + target_ua_allocate_lun(pr_reg_nacl, pr_res_mapped_lun, 0x2A, ASCQ_2AH_REGISTRATIONS_PREEMPTED); } spin_unlock(&pr_tmpl->registration_lock); @@ -3057,7 +3057,7 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key, if (calling_it_nexus) continue; - core_scsi3_ua_allocate(pr_reg->pr_reg_nacl, + target_ua_allocate_lun(pr_reg->pr_reg_nacl, pr_reg->pr_res_mapped_lun, 0x2A, ASCQ_2AH_RESERVATIONS_RELEASED); } diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index eed9580b7f6c..0364534f8d46 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1677,13 +1677,13 @@ void transport_generic_request_failure(struct se_cmd *cmd, * See spc4r17, section 7.4.6 Control Mode Page, Table 349 */ if (cmd->se_sess && - cmd->se_dev->dev_attrib.emulate_ua_intlck_ctrl == 2) - core_scsi3_ua_allocate(cmd->se_sess->se_node_acl, - cmd->orig_fe_lun, 0x2C, - ASCQ_2CH_PREVIOUS_RESERVATION_CONFLICT_STATUS); - + cmd->se_dev->dev_attrib.emulate_ua_intlck_ctrl == 2) { + target_ua_allocate_lun(cmd->se_sess->se_node_acl, + cmd->orig_fe_lun, 0x2C, + ASCQ_2CH_PREVIOUS_RESERVATION_CONFLICT_STATUS); + } trace_target_cmd_complete(cmd); - ret = cmd->se_tfo-> queue_status(cmd); + ret = cmd->se_tfo->queue_status(cmd); if (ret == -EAGAIN || ret == -ENOMEM) goto queue_full; goto check_stop; diff --git a/drivers/target/target_core_ua.c b/drivers/target/target_core_ua.c index e5062245171e..fc095aed5a88 100644 --- a/drivers/target/target_core_ua.c +++ b/drivers/target/target_core_ua.c @@ -87,18 +87,11 @@ target_scsi3_ua_check(struct se_cmd *cmd) } int core_scsi3_ua_allocate( - struct se_node_acl *nacl, - u64 unpacked_lun, + struct se_dev_entry *deve, u8 asc, u8 ascq) { - struct se_dev_entry *deve; struct se_ua *ua, *ua_p, *ua_tmp; - /* - * PASSTHROUGH OPS - */ - if (!nacl) - return -EINVAL; ua = kmem_cache_zalloc(se_ua_cache, GFP_ATOMIC); if (!ua) { @@ -110,12 +103,6 @@ int core_scsi3_ua_allocate( ua->ua_asc = asc; ua->ua_ascq = ascq; - rcu_read_lock(); - deve = target_nacl_find_deve(nacl, unpacked_lun); - if (!deve) { - rcu_read_unlock(); - return -EINVAL; - } spin_lock(&deve->ua_lock); list_for_each_entry_safe(ua_p, ua_tmp, &deve->ua_list, ua_nacl_list) { /* @@ -123,7 +110,6 @@ int core_scsi3_ua_allocate( */ if ((ua_p->ua_asc == asc) && (ua_p->ua_ascq == ascq)) { spin_unlock(&deve->ua_lock); - rcu_read_unlock(); kmem_cache_free(se_ua_cache, ua); return 0; } @@ -170,22 +156,38 @@ int core_scsi3_ua_allocate( spin_unlock(&deve->ua_lock); atomic_inc_mb(&deve->ua_count); - rcu_read_unlock(); return 0; } list_add_tail(&ua->ua_nacl_list, &deve->ua_list); spin_unlock(&deve->ua_lock); - pr_debug("[%s]: Allocated UNIT ATTENTION, mapped LUN: %llu, ASC:" - " 0x%02x, ASCQ: 0x%02x\n", - nacl->se_tpg->se_tpg_tfo->get_fabric_name(), unpacked_lun, + pr_debug("Allocated UNIT ATTENTION, mapped LUN: %llu, ASC:" + " 0x%02x, ASCQ: 0x%02x\n", deve->mapped_lun, asc, ascq); atomic_inc_mb(&deve->ua_count); - rcu_read_unlock(); return 0; } +void target_ua_allocate_lun(struct se_node_acl *nacl, + u32 unpacked_lun, u8 asc, u8 ascq) +{ + struct se_dev_entry *deve; + + if (!nacl) + return; + + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, unpacked_lun); + if (!deve) { + rcu_read_unlock(); + return; + } + + core_scsi3_ua_allocate(deve, asc, ascq); + rcu_read_unlock(); +} + void core_scsi3_ua_release_all( struct se_dev_entry *deve) { diff --git a/drivers/target/target_core_ua.h b/drivers/target/target_core_ua.h index 6e592b10a8c0..96460bff490f 100644 --- a/drivers/target/target_core_ua.h +++ b/drivers/target/target_core_ua.h @@ -28,7 +28,8 @@ extern struct kmem_cache *se_ua_cache; extern sense_reason_t target_scsi3_ua_check(struct se_cmd *); -extern int core_scsi3_ua_allocate(struct se_node_acl *, u64, u8, u8); +extern int core_scsi3_ua_allocate(struct se_dev_entry *, u8, u8); +extern void target_ua_allocate_lun(struct se_node_acl *, u32, u8, u8); extern void core_scsi3_ua_release_all(struct se_dev_entry *); extern void core_scsi3_ua_for_check_condition(struct se_cmd *, u8 *, u8 *); extern int core_scsi3_ua_clear_for_request_sense(struct se_cmd *, -- cgit v1.2.3-70-g09d2 From a01f7cd657c95941079d548ef7fbf0cc370c1259 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Fri, 22 May 2015 15:45:28 -0500 Subject: remoteproc: add a rproc ops for performing address translation The rproc_da_to_va API is currently used to perform any device to kernel address translations to meet the different needs of the remoteproc core/drivers (eg: loading). The functionality is achieved within the remoteproc core, and is limited only for carveouts allocated within the core. A new rproc ops, da_to_va, is added to provide flexibility to platform implementations to perform the address translation themselves when the above conditions cannot be met by the implementations. The rproc_da_to_va() API is extended to invoke this ops if present, and fallback to regular processing if the platform implementation cannot provide the translation. This will allow any remoteproc implementations to translate addresses for dedicated memories like internal memories. While at this, also update the rproc_da_to_va() documentation since it is an exported function. Signed-off-by: Suman Anna Signed-off-by: Dave Gerlach Signed-off-by: Ohad Ben-Cohen --- drivers/remoteproc/remoteproc_core.c | 31 +++++++++++++++++++++++++------ include/linux/remoteproc.h | 2 ++ 2 files changed, 27 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index e1a6d693b8bb..b4ab38015cf2 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -137,28 +137,46 @@ static void rproc_disable_iommu(struct rproc *rproc) iommu_domain_free(domain); } -/* +/** + * rproc_da_to_va() - lookup the kernel virtual address for a remoteproc address + * @rproc: handle of a remote processor + * @da: remoteproc device address to translate + * @len: length of the memory region @da is pointing to + * * Some remote processors will ask us to allocate them physically contiguous * memory regions (which we call "carveouts"), and map them to specific - * device addresses (which are hardcoded in the firmware). + * device addresses (which are hardcoded in the firmware). They may also have + * dedicated memory regions internal to the processors, and use them either + * exclusively or alongside carveouts. * * They may then ask us to copy objects into specific device addresses (e.g. * code/data sections) or expose us certain symbols in other device address * (e.g. their trace buffer). * - * This function is an internal helper with which we can go over the allocated - * carveouts and translate specific device address to kernel virtual addresses - * so we can access the referenced memory. + * This function is a helper function with which we can go over the allocated + * carveouts and translate specific device addresses to kernel virtual addresses + * so we can access the referenced memory. This function also allows to perform + * translations on the internal remoteproc memory regions through a platform + * implementation specific da_to_va ops, if present. + * + * The function returns a valid kernel address on success or NULL on failure. * * Note: phys_to_virt(iommu_iova_to_phys(rproc->domain, da)) will work too, * but only on kernel direct mapped RAM memory. Instead, we're just using - * here the output of the DMA API, which should be more correct. + * here the output of the DMA API for the carveouts, which should be more + * correct. */ void *rproc_da_to_va(struct rproc *rproc, u64 da, int len) { struct rproc_mem_entry *carveout; void *ptr = NULL; + if (rproc->ops->da_to_va) { + ptr = rproc->ops->da_to_va(rproc, da, len); + if (ptr) + goto out; + } + list_for_each_entry(carveout, &rproc->carveouts, node) { int offset = da - carveout->da; @@ -175,6 +193,7 @@ void *rproc_da_to_va(struct rproc *rproc, u64 da, int len) break; } +out: return ptr; } EXPORT_SYMBOL(rproc_da_to_va); diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h index 56739e5df1e6..9c4e1384f636 100644 --- a/include/linux/remoteproc.h +++ b/include/linux/remoteproc.h @@ -330,11 +330,13 @@ struct rproc; * @start: power on the device and boot it * @stop: power off the device * @kick: kick a virtqueue (virtqueue id given as a parameter) + * @da_to_va: optional platform hook to perform address translations */ struct rproc_ops { int (*start)(struct rproc *rproc); int (*stop)(struct rproc *rproc); void (*kick)(struct rproc *rproc, int vqid); + void * (*da_to_va)(struct rproc *rproc, u64 da, int len); }; /** -- cgit v1.2.3-70-g09d2 From a01bc0d5f557bd8becd0ba75d09c39192004697e Mon Sep 17 00:00:00 2001 From: Dave Gerlach Date: Fri, 22 May 2015 15:45:30 -0500 Subject: remoteproc/wkup_m3: add a remoteproc driver for TI Wakeup M3 Add a remoteproc driver to load the firmware and boot a small Wakeup M3 processor present on TI AM33xx and AM43xx SoCs. This Wakeup M3 remote processor is an integrated Cortex M3 that allows the SoC to enter the lowest possible power state by taking control from the MPU after it has gone into its own low power state and shutting off any additional peripherals. The Wakeup M3 processor has two internal memory regions - 16 kB of unified instruction memory called UMEM used to store executable code, and 8 kB of data memory called DMEM used for all data sections. The Wakeup M3 processor executes its code entirely from within the UMEM and uses the DMEM for any data. It does not use any external memory or any other external resources. The device address view has the UMEM at address 0x0 and DMEM at address 0x80000, and these are computed automatically within the driver based on relative address calculation from the corresponding device tree IOMEM resources. These device addresses are used to aid the core remoteproc ELF loader code to properly translate and load the firmware segments through the .rproc_da_to_va ops. Signed-off-by: Dave Gerlach Signed-off-by: Suman Anna Signed-off-by: Ohad Ben-Cohen --- drivers/remoteproc/Kconfig | 13 ++ drivers/remoteproc/Makefile | 1 + drivers/remoteproc/wkup_m3_rproc.c | 257 ++++++++++++++++++++++++++++++++++ include/linux/platform_data/wkup_m3.h | 30 ++++ 4 files changed, 301 insertions(+) create mode 100644 drivers/remoteproc/wkup_m3_rproc.c create mode 100644 include/linux/platform_data/wkup_m3.h (limited to 'drivers') diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index 5e343bab9458..28c711f0ac6b 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -41,6 +41,19 @@ config STE_MODEM_RPROC This can be either built-in or a loadable module. If unsure say N. +config WKUP_M3_RPROC + tristate "AMx3xx Wakeup M3 remoteproc support" + depends on SOC_AM33XX || SOC_AM43XX + select REMOTEPROC + help + Say y here to support Wakeup M3 remote processor on TI AM33xx + and AM43xx family of SoCs. + + Required for Suspend-to-RAM on AM33xx and AM43xx SoCs. Also needed + for deep CPUIdle states on AM33xx SoCs. Allows for loading of the + firmware onto these remote processors. + If unsure say N. + config DA8XX_REMOTEPROC tristate "DA8xx/OMAP-L13x remoteproc support" depends on ARCH_DAVINCI_DA8XX diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile index ac2ff75686d2..81b04d1e2e58 100644 --- a/drivers/remoteproc/Makefile +++ b/drivers/remoteproc/Makefile @@ -9,4 +9,5 @@ remoteproc-y += remoteproc_virtio.o remoteproc-y += remoteproc_elf_loader.o obj-$(CONFIG_OMAP_REMOTEPROC) += omap_remoteproc.o obj-$(CONFIG_STE_MODEM_RPROC) += ste_modem_rproc.o +obj-$(CONFIG_WKUP_M3_RPROC) += wkup_m3_rproc.o obj-$(CONFIG_DA8XX_REMOTEPROC) += da8xx_remoteproc.o diff --git a/drivers/remoteproc/wkup_m3_rproc.c b/drivers/remoteproc/wkup_m3_rproc.c new file mode 100644 index 000000000000..edf81819cce1 --- /dev/null +++ b/drivers/remoteproc/wkup_m3_rproc.c @@ -0,0 +1,257 @@ +/* + * TI AMx3 Wakeup M3 Remote Processor driver + * + * Copyright (C) 2014-2015 Texas Instruments, Inc. + * + * Dave Gerlach + * Suman Anna + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "remoteproc_internal.h" + +#define WKUPM3_MEM_MAX 2 + +/** + * struct wkup_m3_mem - WkupM3 internal memory structure + * @cpu_addr: MPU virtual address of the memory region + * @bus_addr: Bus address used to access the memory region + * @dev_addr: Device address from Wakeup M3 view + * @size: Size of the memory region + */ +struct wkup_m3_mem { + void __iomem *cpu_addr; + phys_addr_t bus_addr; + u32 dev_addr; + size_t size; +}; + +/** + * struct wkup_m3_rproc - WkupM3 remote processor state + * @rproc: rproc handle + * @pdev: pointer to platform device + * @mem: WkupM3 memory information + */ +struct wkup_m3_rproc { + struct rproc *rproc; + struct platform_device *pdev; + struct wkup_m3_mem mem[WKUPM3_MEM_MAX]; +}; + +static int wkup_m3_rproc_start(struct rproc *rproc) +{ + struct wkup_m3_rproc *wkupm3 = rproc->priv; + struct platform_device *pdev = wkupm3->pdev; + struct device *dev = &pdev->dev; + struct wkup_m3_platform_data *pdata = dev_get_platdata(dev); + + if (pdata->deassert_reset(pdev, pdata->reset_name)) { + dev_err(dev, "Unable to reset wkup_m3!\n"); + return -ENODEV; + } + + return 0; +} + +static int wkup_m3_rproc_stop(struct rproc *rproc) +{ + struct wkup_m3_rproc *wkupm3 = rproc->priv; + struct platform_device *pdev = wkupm3->pdev; + struct device *dev = &pdev->dev; + struct wkup_m3_platform_data *pdata = dev_get_platdata(dev); + + if (pdata->assert_reset(pdev, pdata->reset_name)) { + dev_err(dev, "Unable to assert reset of wkup_m3!\n"); + return -ENODEV; + } + + return 0; +} + +static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, int len) +{ + struct wkup_m3_rproc *wkupm3 = rproc->priv; + void *va = NULL; + int i; + u32 offset; + + if (len <= 0) + return NULL; + + for (i = 0; i < WKUPM3_MEM_MAX; i++) { + if (da >= wkupm3->mem[i].dev_addr && da + len <= + wkupm3->mem[i].dev_addr + wkupm3->mem[i].size) { + offset = da - wkupm3->mem[i].dev_addr; + /* __force to make sparse happy with type conversion */ + va = (__force void *)(wkupm3->mem[i].cpu_addr + offset); + break; + } + } + + return va; +} + +static struct rproc_ops wkup_m3_rproc_ops = { + .start = wkup_m3_rproc_start, + .stop = wkup_m3_rproc_stop, + .da_to_va = wkup_m3_rproc_da_to_va, +}; + +static const struct of_device_id wkup_m3_rproc_of_match[] = { + { .compatible = "ti,am3352-wkup-m3", }, + { .compatible = "ti,am4372-wkup-m3", }, + {}, +}; + +static int wkup_m3_rproc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct wkup_m3_platform_data *pdata = dev->platform_data; + /* umem always needs to be processed first */ + const char *mem_names[WKUPM3_MEM_MAX] = { "umem", "dmem" }; + struct wkup_m3_rproc *wkupm3; + const char *fw_name; + struct rproc *rproc; + struct resource *res; + const __be32 *addrp; + u32 l4_offset = 0; + u64 size; + int ret; + int i; + + if (!(pdata && pdata->deassert_reset && pdata->assert_reset && + pdata->reset_name)) { + dev_err(dev, "Platform data missing!\n"); + return -ENODEV; + } + + ret = of_property_read_string(dev->of_node, "ti,pm-firmware", + &fw_name); + if (ret) { + dev_err(dev, "No firmware filename given\n"); + return -ENODEV; + } + + pm_runtime_enable(&pdev->dev); + ret = pm_runtime_get_sync(&pdev->dev); + if (ret < 0) { + dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n"); + goto err; + } + + rproc = rproc_alloc(dev, "wkup_m3", &wkup_m3_rproc_ops, + fw_name, sizeof(*wkupm3)); + if (!rproc) { + ret = -ENOMEM; + goto err; + } + + wkupm3 = rproc->priv; + wkupm3->rproc = rproc; + wkupm3->pdev = pdev; + + for (i = 0; i < ARRAY_SIZE(mem_names); i++) { + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + mem_names[i]); + wkupm3->mem[i].cpu_addr = devm_ioremap_resource(dev, res); + if (IS_ERR(wkupm3->mem[i].cpu_addr)) { + dev_err(&pdev->dev, "devm_ioremap_resource failed for resource %d\n", + i); + ret = PTR_ERR(wkupm3->mem[i].cpu_addr); + goto err; + } + wkupm3->mem[i].bus_addr = res->start; + wkupm3->mem[i].size = resource_size(res); + addrp = of_get_address(dev->of_node, i, &size, NULL); + /* + * The wkupm3 has umem at address 0 in its view, so the device + * addresses for each memory region is computed as a relative + * offset of the bus address for umem, and therefore needs to be + * processed first. + */ + if (!strcmp(mem_names[i], "umem")) + l4_offset = be32_to_cpu(*addrp); + wkupm3->mem[i].dev_addr = be32_to_cpu(*addrp) - l4_offset; + } + + dev_set_drvdata(dev, rproc); + + ret = rproc_add(rproc); + if (ret) { + dev_err(dev, "rproc_add failed\n"); + goto err_put_rproc; + } + + return 0; + +err_put_rproc: + rproc_put(rproc); +err: + pm_runtime_put_noidle(dev); + pm_runtime_disable(dev); + return ret; +} + +static int wkup_m3_rproc_remove(struct platform_device *pdev) +{ + struct rproc *rproc = platform_get_drvdata(pdev); + + rproc_del(rproc); + rproc_put(rproc); + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + + return 0; +} + +#ifdef CONFIG_PM +static int wkup_m3_rpm_suspend(struct device *dev) +{ + return -EBUSY; +} + +static int wkup_m3_rpm_resume(struct device *dev) +{ + return 0; +} +#endif + +static const struct dev_pm_ops wkup_m3_rproc_pm_ops = { + SET_RUNTIME_PM_OPS(wkup_m3_rpm_suspend, wkup_m3_rpm_resume, NULL) +}; + +static struct platform_driver wkup_m3_rproc_driver = { + .probe = wkup_m3_rproc_probe, + .remove = wkup_m3_rproc_remove, + .driver = { + .name = "wkup_m3_rproc", + .of_match_table = wkup_m3_rproc_of_match, + .pm = &wkup_m3_rproc_pm_ops, + }, +}; + +module_platform_driver(wkup_m3_rproc_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("TI Wakeup M3 remote processor control driver"); +MODULE_AUTHOR("Dave Gerlach "); diff --git a/include/linux/platform_data/wkup_m3.h b/include/linux/platform_data/wkup_m3.h new file mode 100644 index 000000000000..3f1d77effd71 --- /dev/null +++ b/include/linux/platform_data/wkup_m3.h @@ -0,0 +1,30 @@ +/* + * TI Wakeup M3 remote processor platform data + * + * Copyright (C) 2014-2015 Texas Instruments, Inc. + * + * Dave Gerlach + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _LINUX_PLATFORM_DATA_WKUP_M3_H +#define _LINUX_PLATFORM_DATA_WKUP_M3_H + +struct platform_device; + +struct wkup_m3_platform_data { + const char *reset_name; + + int (*assert_reset)(struct platform_device *pdev, const char *name); + int (*deassert_reset)(struct platform_device *pdev, const char *name); +}; + +#endif /* _LINUX_PLATFORM_DATA_WKUP_M3_H */ -- cgit v1.2.3-70-g09d2 From 8de3dbd0895bebe52d069a82feae8e3fb51c1bdf Mon Sep 17 00:00:00 2001 From: Ohad Ben-Cohen Date: Thu, 18 Jun 2015 11:44:41 +0300 Subject: remoteproc: fix !CONFIG_OF build breakage Fix this: drivers/remoteproc/remoteproc_core.c: In function 'rproc_get_by_phandle': >> drivers/remoteproc/remoteproc_core.c:1167:2: error: implicit declaration of function 'of_find_node_by_phandle' [-Werror=implicit-function-declaration] np = of_find_node_by_phandle(phandle); Reported-by: kbuild test robot Cc: Dave Gerlach Cc: Suman Anna Signed-off-by: Ohad Ben-Cohen --- drivers/remoteproc/remoteproc_core.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index b4ab38015cf2..8b3130f22b42 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -1178,6 +1178,7 @@ EXPORT_SYMBOL(rproc_shutdown); * * Returns the rproc handle on success, and NULL on failure. */ +#ifdef CONFIG_OF struct rproc *rproc_get_by_phandle(phandle phandle) { struct rproc *rproc = NULL, *r; @@ -1201,6 +1202,12 @@ struct rproc *rproc_get_by_phandle(phandle phandle) return rproc; } +#else +struct rproc *rproc_get_by_phandle(phandle phandle) +{ + return NULL; +} +#endif EXPORT_SYMBOL(rproc_get_by_phandle); /** -- cgit v1.2.3-70-g09d2 From e998200c1912f22cf257ae88771e56de588ee8fb Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 22 Jun 2015 09:22:34 -0700 Subject: Input: imx_keypad - check for clk_prepare_enable() error clk_prepare_enable() may fail, so we should better check its return value and propagate it in the case of error. Signed-off-by: Fabio Estevam Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/imx_keypad.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c index 2e855e6f3565..d2ea863d6a45 100644 --- a/drivers/input/keyboard/imx_keypad.c +++ b/drivers/input/keyboard/imx_keypad.c @@ -506,7 +506,9 @@ static int imx_keypad_probe(struct platform_device *pdev) input_set_drvdata(input_dev, keypad); /* Ensure that the keypad will stay dormant until opened */ - clk_prepare_enable(keypad->clk); + error = clk_prepare_enable(keypad->clk); + if (error) + return error; imx_keypad_inhibit(keypad); clk_disable_unprepare(keypad->clk); -- cgit v1.2.3-70-g09d2 From f992efbb0326ddf57c9d2f759c44a3339ab56a76 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Sun, 21 Jun 2015 10:39:26 +0200 Subject: dell-laptop: Update information about wireless control MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make sure that all existing SMBIOS calls for wireless control are properly documented. This commit also add new documentation released by Dell. Signed-off-by: Pali Rohár Signed-off-by: Darren Hart --- drivers/platform/x86/dell-laptop.c | 158 ++++++++++++++++++++++++++++--------- 1 file changed, 119 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index 83e3d7f9d923..ab89103150b5 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -423,45 +423,125 @@ static inline int dell_smi_error(int value) } } -/* Derived from information in DellWirelessCtl.cpp: - Class 17, select 11 is radio control. It returns an array of 32-bit values. - - Input byte 0 = 0: Wireless information - - result[0]: return code - result[1]: - Bit 0: Hardware switch supported - Bit 1: Wifi locator supported - Bit 2: Wifi is supported - Bit 3: Bluetooth is supported - Bit 4: WWAN is supported - Bit 5: Wireless keyboard supported - Bits 6-7: Reserved - Bit 8: Wifi is installed - Bit 9: Bluetooth is installed - Bit 10: WWAN is installed - Bits 11-15: Reserved - Bit 16: Hardware switch is on - Bit 17: Wifi is blocked - Bit 18: Bluetooth is blocked - Bit 19: WWAN is blocked - Bits 20-31: Reserved - result[2]: NVRAM size in bytes - result[3]: NVRAM format version number - - Input byte 0 = 2: Wireless switch configuration - result[0]: return code - result[1]: - Bit 0: Wifi controlled by switch - Bit 1: Bluetooth controlled by switch - Bit 2: WWAN controlled by switch - Bits 3-6: Reserved - Bit 7: Wireless switch config locked - Bit 8: Wifi locator enabled - Bits 9-14: Reserved - Bit 15: Wifi locator setting locked - Bits 16-31: Reserved -*/ +/* + * Derived from information in smbios-wireless-ctl: + * + * cbSelect 17, Value 11 + * + * Return Wireless Info + * cbArg1, byte0 = 0x00 + * + * cbRes1 Standard return codes (0, -1, -2) + * cbRes2 Info bit flags: + * + * 0 Hardware switch supported (1) + * 1 WiFi locator supported (1) + * 2 WLAN supported (1) + * 3 Bluetooth (BT) supported (1) + * 4 WWAN supported (1) + * 5 Wireless KBD supported (1) + * 6 Uw b supported (1) + * 7 WiGig supported (1) + * 8 WLAN installed (1) + * 9 BT installed (1) + * 10 WWAN installed (1) + * 11 Uw b installed (1) + * 12 WiGig installed (1) + * 13-15 Reserved (0) + * 16 Hardware (HW) switch is On (1) + * 17 WLAN disabled (1) + * 18 BT disabled (1) + * 19 WWAN disabled (1) + * 20 Uw b disabled (1) + * 21 WiGig disabled (1) + * 20-31 Reserved (0) + * + * cbRes3 NVRAM size in bytes + * cbRes4, byte 0 NVRAM format version number + * + * + * Set QuickSet Radio Disable Flag + * cbArg1, byte0 = 0x01 + * cbArg1, byte1 + * Radio ID value: + * 0 Radio Status + * 1 WLAN ID + * 2 BT ID + * 3 WWAN ID + * 4 UWB ID + * 5 WIGIG ID + * cbArg1, byte2 Flag bits: + * 0 QuickSet disables radio (1) + * 1-7 Reserved (0) + * + * cbRes1 Standard return codes (0, -1, -2) + * cbRes2 QuickSet (QS) radio disable bit map: + * 0 QS disables WLAN + * 1 QS disables BT + * 2 QS disables WWAN + * 3 QS disables UWB + * 4 QS disables WIGIG + * 5-31 Reserved (0) + * + * Wireless Switch Configuration + * cbArg1, byte0 = 0x02 + * + * cbArg1, byte1 + * Subcommand: + * 0 Get config + * 1 Set config + * 2 Set WiFi locator enable/disable + * cbArg1,byte2 + * Switch settings (if byte 1==1): + * 0 WLAN sw itch control (1) + * 1 BT sw itch control (1) + * 2 WWAN sw itch control (1) + * 3 UWB sw itch control (1) + * 4 WiGig sw itch control (1) + * 5-7 Reserved (0) + * cbArg1, byte2 Enable bits (if byte 1==2): + * 0 Enable WiFi locator (1) + * + * cbRes1 Standard return codes (0, -1, -2) + * cbRes2 QuickSet radio disable bit map: + * 0 WLAN controlled by sw itch (1) + * 1 BT controlled by sw itch (1) + * 2 WWAN controlled by sw itch (1) + * 3 UWB controlled by sw itch (1) + * 4 WiGig controlled by sw itch (1) + * 5-6 Reserved (0) + * 7 Wireless sw itch config locked (1) + * 8 WiFi locator enabled (1) + * 9-14 Reserved (0) + * 15 WiFi locator setting locked (1) + * 16-31 Reserved (0) + * + * Read Local Config Data (LCD) + * cbArg1, byte0 = 0x10 + * cbArg1, byte1 NVRAM index low byte + * cbArg1, byte2 NVRAM index high byte + * cbRes1 Standard return codes (0, -1, -2) + * cbRes2 4 bytes read from LCD[index] + * cbRes3 4 bytes read from LCD[index+4] + * cbRes4 4 bytes read from LCD[index+8] + * + * Write Local Config Data (LCD) + * cbArg1, byte0 = 0x11 + * cbArg1, byte1 NVRAM index low byte + * cbArg1, byte2 NVRAM index high byte + * cbArg2 4 bytes to w rite at LCD[index] + * cbArg3 4 bytes to w rite at LCD[index+4] + * cbArg4 4 bytes to w rite at LCD[index+8] + * cbRes1 Standard return codes (0, -1, -2) + * + * Populate Local Config Data from NVRAM + * cbArg1, byte0 = 0x12 + * cbRes1 Standard return codes (0, -1, -2) + * + * Commit Local Config Data to NVRAM + * cbArg1, byte0 = 0x13 + * cbRes1 Standard return codes (0, -1, -2) + */ static int dell_rfkill_set(void *data, bool blocked) { -- cgit v1.2.3-70-g09d2 From 2e19f93fecc502e68131e4433ef8d57ffa22bc3b Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Sun, 21 Jun 2015 10:41:42 +0200 Subject: dell-laptop: Show info about WiGig and UWB in debugfs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit show additional information about rfkill state in debugfs based on newly released documentation by Dell. Signed-off-by: Pali Rohár Signed-off-by: Darren Hart --- drivers/platform/x86/dell-laptop.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index ab89103150b5..9724613c28a6 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -629,12 +629,21 @@ static int dell_debugfs_show(struct seq_file *s, void *data) (status & BIT(4)) >> 4); seq_printf(s, "Bit 5 : Wireless keyboard supported: %lu\n", (status & BIT(5)) >> 5); + seq_printf(s, "Bit 6 : UWB supported: %lu\n", + (status & BIT(6)) >> 6); + seq_printf(s, "Bit 7 : WiGig supported: %lu\n", + (status & BIT(7)) >> 7); seq_printf(s, "Bit 8 : Wifi is installed: %lu\n", (status & BIT(8)) >> 8); seq_printf(s, "Bit 9 : Bluetooth is installed: %lu\n", (status & BIT(9)) >> 9); seq_printf(s, "Bit 10: WWAN is installed: %lu\n", (status & BIT(10)) >> 10); + seq_printf(s, "Bit 11: UWB installed: %lu\n", + (status & BIT(11)) >> 11); + seq_printf(s, "Bit 12: WiGig installed: %lu\n", + (status & BIT(12)) >> 12); + seq_printf(s, "Bit 16: Hardware switch is on: %lu\n", (status & BIT(16)) >> 16); seq_printf(s, "Bit 17: Wifi is blocked: %lu\n", @@ -643,6 +652,10 @@ static int dell_debugfs_show(struct seq_file *s, void *data) (status & BIT(18)) >> 18); seq_printf(s, "Bit 19: WWAN is blocked: %lu\n", (status & BIT(19)) >> 19); + seq_printf(s, "Bit 20: UWB is blocked: %lu\n", + (status & BIT(20)) >> 20); + seq_printf(s, "Bit 21: WiGig is blocked: %lu\n", + (status & BIT(21)) >> 21); seq_printf(s, "\nhwswitch_state:\t0x%X\n", hwswitch_state); seq_printf(s, "Bit 0 : Wifi controlled by switch: %lu\n", @@ -651,6 +664,10 @@ static int dell_debugfs_show(struct seq_file *s, void *data) (hwswitch_state & BIT(1)) >> 1); seq_printf(s, "Bit 2 : WWAN controlled by switch: %lu\n", (hwswitch_state & BIT(2)) >> 2); + seq_printf(s, "Bit 3 : UWB controlled by switch: %lu\n", + (hwswitch_state & BIT(3)) >> 3); + seq_printf(s, "Bit 4 : WiGig controlled by switch: %lu\n", + (hwswitch_state & BIT(4)) >> 4); seq_printf(s, "Bit 7 : Wireless switch config locked: %lu\n", (hwswitch_state & BIT(7)) >> 7); seq_printf(s, "Bit 8 : Wifi locator enabled: %lu\n", -- cgit v1.2.3-70-g09d2 From 75b7f05d2798ee3a1cc5bbdd54acd0e318a80396 Mon Sep 17 00:00:00 2001 From: "Pierre-Loup A. Griffais" Date: Mon, 22 Jun 2015 14:10:36 -0700 Subject: Input: xpad - set the LEDs properly on XBox Wireless controllers Based on Patch by Pierre-Loup A. Griffais : Add the logic to set the LEDs on XBox Wireless controllers. Command sequence found by sniffing the Windows data stream when plugging the device in. Updated based on comments on linux-input: unify codepaths in xpad_send_led_command for wired/ wireless controller. Also document command values for clarification. All values tested on Xbox 360 Wireless Controller. Signed-off-by: Pavel Rojtberg Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/xpad.c | 50 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 61c761156371..6f8755e2c491 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -881,17 +881,57 @@ struct xpad_led { struct usb_xpad *xpad; }; +/** + * @param command + * 0: off + * 1: all blink, then previous setting + * 2: 1/top-left blink, then on + * 3: 2/top-right blink, then on + * 4: 3/bottom-left blink, then on + * 5: 4/bottom-right blink, then on + * 6: 1/top-left on + * 7: 2/top-right on + * 8: 3/bottom-left on + * 9: 4/bottom-right on + * 10: rotate + * 11: blink, based on previous setting + * 12: slow blink, based on previous setting + * 13: rotate with two lights + * 14: persistent slow all blink + * 15: blink once, then previous setting + */ static void xpad_send_led_command(struct usb_xpad *xpad, int command) { - if (command >= 0 && command < 14) { - mutex_lock(&xpad->odata_mutex); + command %= 16; + + mutex_lock(&xpad->odata_mutex); + + switch (xpad->xtype) { + case XTYPE_XBOX360: xpad->odata[0] = 0x01; xpad->odata[1] = 0x03; xpad->odata[2] = command; xpad->irq_out->transfer_buffer_length = 3; - usb_submit_urb(xpad->irq_out, GFP_KERNEL); - mutex_unlock(&xpad->odata_mutex); + break; + case XTYPE_XBOX360W: + xpad->odata[0] = 0x00; + xpad->odata[1] = 0x00; + xpad->odata[2] = 0x08; + xpad->odata[3] = 0x40 + command; + xpad->odata[4] = 0x00; + xpad->odata[5] = 0x00; + xpad->odata[6] = 0x00; + xpad->odata[7] = 0x00; + xpad->odata[8] = 0x00; + xpad->odata[9] = 0x00; + xpad->odata[10] = 0x00; + xpad->odata[11] = 0x00; + xpad->irq_out->transfer_buffer_length = 12; + break; } + + usb_submit_urb(xpad->irq_out, GFP_KERNEL); + mutex_unlock(&xpad->odata_mutex); } static void xpad_led_set(struct led_classdev *led_cdev, @@ -911,7 +951,7 @@ static int xpad_led_probe(struct usb_xpad *xpad) struct led_classdev *led_cdev; int error; - if (xpad->xtype != XTYPE_XBOX360) + if (xpad->xtype != XTYPE_XBOX360 && xpad->xtype != XTYPE_XBOX360W) return 0; xpad->led = led = kzalloc(sizeof(struct xpad_led), GFP_KERNEL); -- cgit v1.2.3-70-g09d2 From cae705baa40b2c20de8f9bb79ef4bcc6b2418c7c Mon Sep 17 00:00:00 2001 From: Pavel Rojtberg Date: Mon, 22 Jun 2015 14:11:30 -0700 Subject: Input: xpad - re-send LED command on present event The controller only receives commands when its present. So for the correct LED to be lit the LED command has to be sent on the present event. Signed-off-by: Pavel Rojtberg Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/xpad.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 6f8755e2c491..f8850f9cb331 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -344,6 +344,7 @@ struct usb_xpad { int mapping; /* map d-pad to buttons or to axes */ int xtype; /* type of xbox device */ + unsigned long led_no; /* led to lit on xbox360 controllers */ }; /* @@ -488,6 +489,8 @@ static void xpad360_process_packet(struct usb_xpad *xpad, input_sync(dev); } +static void xpad_identify_controller(struct usb_xpad *xpad); + /* * xpad360w_process_packet * @@ -510,6 +513,11 @@ static void xpad360w_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned cha if (data[1] & 0x80) { xpad->pad_present = 1; usb_submit_urb(xpad->bulk_out, GFP_ATOMIC); + /* + * Light up the segment corresponding to + * controller number. + */ + xpad_identify_controller(xpad); } else xpad->pad_present = 0; } @@ -934,6 +942,12 @@ static void xpad_send_led_command(struct usb_xpad *xpad, int command) mutex_unlock(&xpad->odata_mutex); } +static void xpad_identify_controller(struct usb_xpad *xpad) +{ + /* Light up the segment corresponding to controller number */ + xpad_send_led_command(xpad, (xpad->led_no % 4) + 2); +} + static void xpad_led_set(struct led_classdev *led_cdev, enum led_brightness value) { @@ -945,8 +959,7 @@ static void xpad_led_set(struct led_classdev *led_cdev, static int xpad_led_probe(struct usb_xpad *xpad) { - static atomic_t led_seq = ATOMIC_INIT(-1); - unsigned long led_no; + static atomic_t led_seq = ATOMIC_INIT(-1); struct xpad_led *led; struct led_classdev *led_cdev; int error; @@ -958,9 +971,9 @@ static int xpad_led_probe(struct usb_xpad *xpad) if (!led) return -ENOMEM; - led_no = atomic_inc_return(&led_seq); + xpad->led_no = atomic_inc_return(&led_seq); - snprintf(led->name, sizeof(led->name), "xpad%lu", led_no); + snprintf(led->name, sizeof(led->name), "xpad%lu", xpad->led_no); led->xpad = xpad; led_cdev = &led->led_cdev; @@ -974,10 +987,8 @@ static int xpad_led_probe(struct usb_xpad *xpad) return error; } - /* - * Light up the segment corresponding to controller number - */ - xpad_send_led_command(xpad, (led_no % 4) + 2); + /* Light up the segment corresponding to controller number */ + xpad_identify_controller(xpad); return 0; } @@ -994,6 +1005,7 @@ static void xpad_led_disconnect(struct usb_xpad *xpad) #else static int xpad_led_probe(struct usb_xpad *xpad) { return 0; } static void xpad_led_disconnect(struct usb_xpad *xpad) { } +static void xpad_identify_controller(struct usb_xpad *xpad) { } #endif -- cgit v1.2.3-70-g09d2 From 1adff1b3a7f75a1c255b7fcab5676edf29d4a5d8 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Mon, 22 Jun 2015 23:44:05 -0700 Subject: target: Convert se_lun->lun_deve_lock to normal spinlock This patch converts se_lun->lun_deve_lock acquire/release access to use a normal, non bottom-half spin_lock_t for protecting se_lun->lun_deve_list access. Reported-by: Christoph Hellwig Cc: Hannes Reinecke Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_alua.c | 4 ++-- drivers/target/target_core_device.c | 12 ++++++------ drivers/target/target_core_pr.c | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index aa2e4b103d43..c56ae024c42e 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -968,7 +968,7 @@ static void core_alua_queue_state_change_ua(struct t10_alua_tg_pt_gp *tg_pt_gp) continue; spin_unlock(&tg_pt_gp->tg_pt_gp_lock); - spin_lock_bh(&lun->lun_deve_lock); + spin_lock(&lun->lun_deve_lock); list_for_each_entry(se_deve, &lun->lun_deve_list, lun_link) { lacl = rcu_dereference_check(se_deve->se_lun_acl, lockdep_is_held(&lun->lun_deve_lock)); @@ -1000,7 +1000,7 @@ static void core_alua_queue_state_change_ua(struct t10_alua_tg_pt_gp *tg_pt_gp) core_scsi3_ua_allocate(se_deve, 0x2A, ASCQ_2AH_ASYMMETRIC_ACCESS_STATE_CHANGED); } - spin_unlock_bh(&lun->lun_deve_lock); + spin_unlock(&lun->lun_deve_lock); spin_lock(&tg_pt_gp->tg_pt_gp_lock); percpu_ref_put(&lun->lun_ref); diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index ed084023e7d4..b6df5b9a6890 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -352,10 +352,10 @@ int core_enable_device_list_for_node( hlist_add_head_rcu(&new->link, &nacl->lun_entry_hlist); mutex_unlock(&nacl->lun_entry_mutex); - spin_lock_bh(&lun->lun_deve_lock); + spin_lock(&lun->lun_deve_lock); list_del(&orig->lun_link); list_add_tail(&new->lun_link, &lun->lun_deve_list); - spin_unlock_bh(&lun->lun_deve_lock); + spin_unlock(&lun->lun_deve_lock); kref_put(&orig->pr_kref, target_pr_kref_release); wait_for_completion(&orig->pr_comp); @@ -369,9 +369,9 @@ int core_enable_device_list_for_node( hlist_add_head_rcu(&new->link, &nacl->lun_entry_hlist); mutex_unlock(&nacl->lun_entry_mutex); - spin_lock_bh(&lun->lun_deve_lock); + spin_lock(&lun->lun_deve_lock); list_add_tail(&new->lun_link, &lun->lun_deve_list); - spin_unlock_bh(&lun->lun_deve_lock); + spin_unlock(&lun->lun_deve_lock); return 0; } @@ -403,9 +403,9 @@ void core_disable_device_list_for_node( * NodeACL context specific PR metadata for demo-mode * MappedLUN *deve will be released below.. */ - spin_lock_bh(&lun->lun_deve_lock); + spin_lock(&lun->lun_deve_lock); list_del(&orig->lun_link); - spin_unlock_bh(&lun->lun_deve_lock); + spin_unlock(&lun->lun_deve_lock); /* * Disable struct se_dev_entry LUN ACL mapping */ diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 0bb329243dba..7403b03d428f 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -709,7 +709,7 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( continue; spin_unlock(&dev->se_port_lock); - spin_lock_bh(&lun_tmp->lun_deve_lock); + spin_lock(&lun_tmp->lun_deve_lock); list_for_each_entry(deve_tmp, &lun_tmp->lun_deve_list, lun_link) { /* * This pointer will be NULL for demo mode MappedLUNs @@ -742,7 +742,7 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( continue; kref_get(&deve_tmp->pr_kref); - spin_unlock_bh(&lun_tmp->lun_deve_lock); + spin_unlock(&lun_tmp->lun_deve_lock); /* * Grab a configfs group dependency that is released * for the exception path at label out: below, or upon @@ -779,9 +779,9 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( list_add_tail(&pr_reg_atp->pr_reg_atp_mem_list, &pr_reg->pr_reg_atp_list); - spin_lock_bh(&lun_tmp->lun_deve_lock); + spin_lock(&lun_tmp->lun_deve_lock); } - spin_unlock_bh(&lun_tmp->lun_deve_lock); + spin_unlock(&lun_tmp->lun_deve_lock); spin_lock(&dev->se_port_lock); percpu_ref_put(&lun_tmp->lun_ref); -- cgit v1.2.3-70-g09d2 From 3dd348fcaa407181585fcadc04b0cac6e31f9be0 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 11 Jun 2015 10:01:27 +0200 Subject: target: Send UA on ALUA target port group change When the ALUA target port group changes an INQUIRY DATA CHANGE UA needs to be sent. Signed-off-by: Hannes Reinecke Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_alua.c | 7 +++++++ drivers/target/target_core_ua.h | 2 ++ 2 files changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index c56ae024c42e..744f308053e0 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -1880,12 +1880,19 @@ static void core_alua_put_tg_pt_gp_from_name( static void __target_attach_tg_pt_gp(struct se_lun *lun, struct t10_alua_tg_pt_gp *tg_pt_gp) { + struct se_dev_entry *se_deve; + assert_spin_locked(&lun->lun_tg_pt_gp_lock); spin_lock(&tg_pt_gp->tg_pt_gp_lock); lun->lun_tg_pt_gp = tg_pt_gp; list_add_tail(&lun->lun_tg_pt_gp_link, &tg_pt_gp->tg_pt_gp_lun_list); tg_pt_gp->tg_pt_gp_members++; + spin_lock(&lun->lun_deve_lock); + list_for_each_entry(se_deve, &lun->lun_deve_list, lun_link) + core_scsi3_ua_allocate(se_deve, 0x3f, + ASCQ_3FH_INQUIRY_DATA_HAS_CHANGED); + spin_unlock(&lun->lun_deve_lock); spin_unlock(&tg_pt_gp->tg_pt_gp_lock); } diff --git a/drivers/target/target_core_ua.h b/drivers/target/target_core_ua.h index 96460bff490f..59278d662e66 100644 --- a/drivers/target/target_core_ua.h +++ b/drivers/target/target_core_ua.h @@ -25,6 +25,8 @@ #define ASCQ_2CH_PREVIOUS_RESERVATION_CONFLICT_STATUS 0x09 +#define ASCQ_3FH_INQUIRY_DATA_HAS_CHANGED 0x03 + extern struct kmem_cache *se_ua_cache; extern sense_reason_t target_scsi3_ua_check(struct se_cmd *); -- cgit v1.2.3-70-g09d2 From b5aafb16ebdb713e9e5ac60db2940fe4baf6328f Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 11 Jun 2015 10:01:28 +0200 Subject: target: Send UA upon LUN RESET tmr completion SAM mandates that an BUS DEVICE RESET FUNCTION OCCURRED UA needs to be send after a LUN RESET tmr has completed. (Update to use target_ua_allocate_lun - hch) Signed-off-by: Hannes Reinecke Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 0364534f8d46..e5088c059b4f 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2983,6 +2983,11 @@ static void target_tmr_work(struct work_struct *work) ret = core_tmr_lun_reset(dev, tmr, NULL, NULL); tmr->response = (!ret) ? TMR_FUNCTION_COMPLETE : TMR_FUNCTION_REJECTED; + if (tmr->response == TMR_FUNCTION_COMPLETE) { + target_ua_allocate_lun(cmd->se_sess->se_node_acl, + cmd->orig_fe_lun, 0x29, + ASCQ_29H_BUS_DEVICE_RESET_FUNCTION_OCCURRED); + } break; case TMR_TARGET_WARM_RESET: tmr->response = TMR_FUNCTION_REJECTED; -- cgit v1.2.3-70-g09d2 From 7c0d0d51d26497866d2951a35f1736fc765e4fcf Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 11 Jun 2015 10:01:29 +0200 Subject: target: Send UA when changing LUN inventory When changind the LUN inventory via core_enable_device_list_for_node() or core_disable_device_list_for_node() a REPORTED LUNS DATA HAS CHANGED UA should be send. (Convert to target_luns_data_has_changed helper usage - hch) Signed-off-by: Hannes Reinecke Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_device.c | 23 +++++++++++++++++++---- drivers/target/target_core_ua.h | 1 + 2 files changed, 20 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index b6df5b9a6890..52448483ed9b 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -293,10 +293,22 @@ void target_pr_kref_release(struct kref *kref) complete(&deve->pr_comp); } -/* core_enable_device_list_for_node(): - * - * - */ +static void +target_luns_data_has_changed(struct se_node_acl *nacl, struct se_dev_entry *new, + bool skip_new) +{ + struct se_dev_entry *tmp; + + rcu_read_lock(); + hlist_for_each_entry_rcu(tmp, &nacl->lun_entry_hlist, link) { + if (skip_new && tmp == new) + continue; + core_scsi3_ua_allocate(tmp, 0x3F, + ASCQ_3FH_REPORTED_LUNS_DATA_HAS_CHANGED); + } + rcu_read_unlock(); +} + int core_enable_device_list_for_node( struct se_lun *lun, struct se_lun_acl *lun_acl, @@ -360,6 +372,7 @@ int core_enable_device_list_for_node( kref_put(&orig->pr_kref, target_pr_kref_release); wait_for_completion(&orig->pr_comp); + target_luns_data_has_changed(nacl, new, true); kfree_rcu(orig, rcu_head); return 0; } @@ -373,6 +386,7 @@ int core_enable_device_list_for_node( list_add_tail(&new->lun_link, &lun->lun_deve_list); spin_unlock(&lun->lun_deve_lock); + target_luns_data_has_changed(nacl, new, true); return 0; } @@ -428,6 +442,7 @@ void core_disable_device_list_for_node( kfree_rcu(orig, rcu_head); core_scsi3_free_pr_reg_from_nacl(dev, nacl); + target_luns_data_has_changed(nacl, NULL, false); } /* core_clear_lun_from_tpg(): diff --git a/drivers/target/target_core_ua.h b/drivers/target/target_core_ua.h index 59278d662e66..bd6e78ba153d 100644 --- a/drivers/target/target_core_ua.h +++ b/drivers/target/target_core_ua.h @@ -26,6 +26,7 @@ #define ASCQ_2CH_PREVIOUS_RESERVATION_CONFLICT_STATUS 0x09 #define ASCQ_3FH_INQUIRY_DATA_HAS_CHANGED 0x03 +#define ASCQ_3FH_REPORTED_LUNS_DATA_HAS_CHANGED 0x0E extern struct kmem_cache *se_ua_cache; -- cgit v1.2.3-70-g09d2 From e2e21bd8f979a24462070cc89fae11e819cae90a Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Thu, 11 Jun 2015 19:58:34 +0300 Subject: target/user: Fix inconsistent kmap_atomic/kunmap_atomic Pointers that are mapped by kmap_atomic() + offset must be unmapped without the offset. That would cause problems if the SG element length exceeds the PAGE_SIZE limit. Signed-off-by: Sagi Grimberg Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_user.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 949e6165ef8a..078ef6e3eb70 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -260,7 +260,8 @@ static void alloc_and_scatter_data_area(struct tcmu_dev *udev, /* Uh oh, we wrapped the buffer. Must split sg across 2 iovs. */ if (sg->length != copy_bytes) { - from += copy_bytes; + void *from_skip = from + copy_bytes; + copy_bytes = sg->length - copy_bytes; (*iov)->iov_len = copy_bytes; @@ -270,7 +271,7 @@ static void alloc_and_scatter_data_area(struct tcmu_dev *udev, if (copy_data) { to = (void *) udev->mb_addr + udev->data_off + udev->data_head; - memcpy(to, from, copy_bytes); + memcpy(to, from_skip, copy_bytes); tcmu_flush_dcache_range(to, copy_bytes); } @@ -281,7 +282,7 @@ static void alloc_and_scatter_data_area(struct tcmu_dev *udev, copy_bytes, udev->data_size); } - kunmap_atomic(from); + kunmap_atomic(from - sg->offset); } } @@ -309,18 +310,19 @@ static void gather_and_free_data_area(struct tcmu_dev *udev, /* Uh oh, wrapped the data buffer for this sg's data */ if (sg->length != copy_bytes) { + void *to_skip = to + copy_bytes; + from = (void *) udev->mb_addr + udev->data_off + udev->data_tail; WARN_ON(udev->data_tail); - to += copy_bytes; copy_bytes = sg->length - copy_bytes; tcmu_flush_dcache_range(from, copy_bytes); - memcpy(to, from, copy_bytes); + memcpy(to_skip, from, copy_bytes); UPDATE_HEAD(udev->data_tail, copy_bytes, udev->data_size); } - kunmap_atomic(to); + kunmap_atomic(to - sg->offset); } } -- cgit v1.2.3-70-g09d2 From 7a971b1b3055f0e76ff09b8fd0dd809ea3b48279 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 19 Jun 2015 15:10:58 +0200 Subject: target: replace se_cmd->execute_rw with a protocol_data field Instead of leaking this SBC read/write implementation detail just add an opaqueue protocol specific pointer to struct se_cmd that we can assign the sbc_ops vector to. Signed-off-by: Christoph Hellwig Reviewed-by: Andy Grover Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_sbc.c | 20 +++++++------------- include/target/target_core_base.h | 3 +-- 2 files changed, 8 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 31b2ae356120..287843e19275 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -381,7 +381,9 @@ out: static sense_reason_t sbc_execute_rw(struct se_cmd *cmd) { - return cmd->execute_rw(cmd, cmd->t_data_sg, cmd->t_data_nents, + struct sbc_ops *ops = cmd->protocol_data; + + return ops->execute_rw(cmd, cmd->t_data_sg, cmd->t_data_nents, cmd->data_direction); } @@ -560,6 +562,7 @@ out: static sense_reason_t sbc_compare_and_write(struct se_cmd *cmd) { + struct sbc_ops *ops = cmd->protocol_data; struct se_device *dev = cmd->se_dev; sense_reason_t ret; int rc; @@ -579,7 +582,7 @@ sbc_compare_and_write(struct se_cmd *cmd) */ cmd->data_length = cmd->t_task_nolb * dev->dev_attrib.block_size; - ret = cmd->execute_rw(cmd, cmd->t_bidi_data_sg, cmd->t_bidi_data_nents, + ret = ops->execute_rw(cmd, cmd->t_bidi_data_sg, cmd->t_bidi_data_nents, DMA_FROM_DEVICE); if (ret) { cmd->transport_complete_callback = NULL; @@ -766,12 +769,13 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) u32 sectors = 0; sense_reason_t ret; + cmd->protocol_data = ops; + switch (cdb[0]) { case READ_6: sectors = transport_get_sectors_6(cdb); cmd->t_task_lba = transport_lba_21(cdb); cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - cmd->execute_rw = ops->execute_rw; cmd->execute_cmd = sbc_execute_rw; break; case READ_10: @@ -786,7 +790,6 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) return ret; cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - cmd->execute_rw = ops->execute_rw; cmd->execute_cmd = sbc_execute_rw; break; case READ_12: @@ -801,7 +804,6 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) return ret; cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - cmd->execute_rw = ops->execute_rw; cmd->execute_cmd = sbc_execute_rw; break; case READ_16: @@ -816,14 +818,12 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) return ret; cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - cmd->execute_rw = ops->execute_rw; cmd->execute_cmd = sbc_execute_rw; break; case WRITE_6: sectors = transport_get_sectors_6(cdb); cmd->t_task_lba = transport_lba_21(cdb); cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - cmd->execute_rw = ops->execute_rw; cmd->execute_cmd = sbc_execute_rw; break; case WRITE_10: @@ -839,7 +839,6 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) return ret; cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - cmd->execute_rw = ops->execute_rw; cmd->execute_cmd = sbc_execute_rw; break; case WRITE_12: @@ -854,7 +853,6 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) return ret; cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - cmd->execute_rw = ops->execute_rw; cmd->execute_cmd = sbc_execute_rw; break; case WRITE_16: @@ -869,7 +867,6 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) return ret; cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - cmd->execute_rw = ops->execute_rw; cmd->execute_cmd = sbc_execute_rw; break; case XDWRITEREAD_10: @@ -887,7 +884,6 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) /* * Setup BIDI XOR callback to be run after I/O completion. */ - cmd->execute_rw = ops->execute_rw; cmd->execute_cmd = sbc_execute_rw; cmd->transport_complete_callback = &xdreadwrite_callback; break; @@ -911,7 +907,6 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) * Setup BIDI XOR callback to be run during after I/O * completion. */ - cmd->execute_rw = ops->execute_rw; cmd->execute_cmd = sbc_execute_rw; cmd->transport_complete_callback = &xdreadwrite_callback; break; @@ -955,7 +950,6 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) cmd->t_task_lba = get_unaligned_be64(&cdb[2]); cmd->t_task_nolb = sectors; cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB | SCF_COMPARE_AND_WRITE; - cmd->execute_rw = ops->execute_rw; cmd->execute_cmd = sbc_compare_and_write; cmd->transport_complete_callback = compare_and_write_callback; break; diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 8a4f861f12b7..273818403a3e 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -490,9 +490,8 @@ struct se_cmd { struct kref cmd_kref; const struct target_core_fabric_ops *se_tfo; sense_reason_t (*execute_cmd)(struct se_cmd *); - sense_reason_t (*execute_rw)(struct se_cmd *, struct scatterlist *, - u32, enum dma_data_direction); sense_reason_t (*transport_complete_callback)(struct se_cmd *, bool); + void *protocol_data; unsigned char *t_task_cdb; unsigned char __t_task_cdb[TCM_MAX_COMMAND_SIZE]; -- cgit v1.2.3-70-g09d2 From 62e4694256dd3cbe301ebc0da799df8779b97014 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 19 Jun 2015 15:10:59 +0200 Subject: target: simplify UNMAP handling Move a little more processing into the core code, and lift the previous do_unmap callback into the sbc_ops structure. Signed-off-by: Christoph Hellwig Reviewed-by: Andy Grover Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_file.c | 17 +++-------------- drivers/target/target_core_iblock.c | 16 +++------------- drivers/target/target_core_sbc.c | 14 ++++++-------- include/target/target_core_backend.h | 7 ++----- 4 files changed, 14 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index 238e3a256d04..ced8c4fdc23d 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -475,9 +475,9 @@ fd_do_prot_unmap(struct se_cmd *cmd, sector_t lba, sector_t nolb) } static sense_reason_t -fd_do_unmap(struct se_cmd *cmd, void *priv, sector_t lba, sector_t nolb) +fd_execute_unmap(struct se_cmd *cmd, sector_t lba, sector_t nolb) { - struct file *file = priv; + struct file *file = FD_DEV(cmd->se_dev)->fd_file; struct inode *inode = file->f_mapping->host; int ret; @@ -521,9 +521,6 @@ fd_do_unmap(struct se_cmd *cmd, void *priv, sector_t lba, sector_t nolb) static sense_reason_t fd_execute_write_same_unmap(struct se_cmd *cmd) { - struct se_device *se_dev = cmd->se_dev; - struct fd_dev *fd_dev = FD_DEV(se_dev); - struct file *file = fd_dev->fd_file; sector_t lba = cmd->t_task_lba; sector_t nolb = sbc_get_write_same_sectors(cmd); sense_reason_t ret; @@ -533,7 +530,7 @@ fd_execute_write_same_unmap(struct se_cmd *cmd) return 0; } - ret = fd_do_unmap(cmd, file, lba, nolb); + ret = fd_execute_unmap(cmd, lba, nolb); if (ret) return ret; @@ -541,14 +538,6 @@ fd_execute_write_same_unmap(struct se_cmd *cmd) return 0; } -static sense_reason_t -fd_execute_unmap(struct se_cmd *cmd) -{ - struct file *file = FD_DEV(cmd->se_dev)->fd_file; - - return sbc_execute_unmap(cmd, fd_do_unmap, file); -} - static sense_reason_t fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, enum dma_data_direction data_direction) diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index ae8ad2da6632..0a2308891c81 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -416,10 +416,9 @@ iblock_execute_sync_cache(struct se_cmd *cmd) } static sense_reason_t -iblock_do_unmap(struct se_cmd *cmd, void *priv, - sector_t lba, sector_t nolb) +iblock_execute_unmap(struct se_cmd *cmd, sector_t lba, sector_t nolb) { - struct block_device *bdev = priv; + struct block_device *bdev = IBLOCK_DEV(cmd->se_dev)->ibd_bd; int ret; ret = blkdev_issue_discard(bdev, lba, nolb, GFP_KERNEL, 0); @@ -431,23 +430,14 @@ iblock_do_unmap(struct se_cmd *cmd, void *priv, return 0; } -static sense_reason_t -iblock_execute_unmap(struct se_cmd *cmd) -{ - struct block_device *bdev = IBLOCK_DEV(cmd->se_dev)->ibd_bd; - - return sbc_execute_unmap(cmd, iblock_do_unmap, bdev); -} - static sense_reason_t iblock_execute_write_same_unmap(struct se_cmd *cmd) { - struct block_device *bdev = IBLOCK_DEV(cmd->se_dev)->ibd_bd; sector_t lba = cmd->t_task_lba; sector_t nolb = sbc_get_write_same_sectors(cmd); sense_reason_t ret; - ret = iblock_do_unmap(cmd, bdev, lba, nolb); + ret = iblock_execute_unmap(cmd, lba, nolb); if (ret) return ret; diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 287843e19275..c16a66698725 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -38,6 +38,7 @@ static sense_reason_t sbc_check_prot(struct se_device *, struct se_cmd *, unsigned char *, u32, bool); +static sense_reason_t sbc_execute_unmap(struct se_cmd *cmd); static sense_reason_t sbc_emulate_readcapacity(struct se_cmd *cmd) @@ -999,7 +1000,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) return TCM_UNSUPPORTED_SCSI_OPCODE; } size = get_unaligned_be16(&cdb[7]); - cmd->execute_cmd = ops->execute_unmap; + cmd->execute_cmd = sbc_execute_unmap; break; case WRITE_SAME_16: sectors = transport_get_sectors_16(cdb); @@ -1087,12 +1088,10 @@ u32 sbc_get_device_type(struct se_device *dev) } EXPORT_SYMBOL(sbc_get_device_type); -sense_reason_t -sbc_execute_unmap(struct se_cmd *cmd, - sense_reason_t (*do_unmap_fn)(struct se_cmd *, void *, - sector_t, sector_t), - void *priv) +static sense_reason_t +sbc_execute_unmap(struct se_cmd *cmd) { + struct sbc_ops *ops = cmd->protocol_data; struct se_device *dev = cmd->se_dev; unsigned char *buf, *ptr = NULL; sector_t lba; @@ -1156,7 +1155,7 @@ sbc_execute_unmap(struct se_cmd *cmd, goto err; } - ret = do_unmap_fn(cmd, priv, lba, range); + ret = ops->execute_unmap(cmd, lba, range); if (ret) goto err; @@ -1170,7 +1169,6 @@ err: target_complete_cmd(cmd, GOOD); return ret; } -EXPORT_SYMBOL(sbc_execute_unmap); void sbc_dif_generate(struct se_cmd *cmd) diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index 566c7d27f6d0..ff399369a21a 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -50,7 +50,8 @@ struct sbc_ops { sense_reason_t (*execute_sync_cache)(struct se_cmd *cmd); sense_reason_t (*execute_write_same)(struct se_cmd *cmd); sense_reason_t (*execute_write_same_unmap)(struct se_cmd *cmd); - sense_reason_t (*execute_unmap)(struct se_cmd *cmd); + sense_reason_t (*execute_unmap)(struct se_cmd *cmd, + sector_t lba, sector_t nolb); }; int transport_backend_register(const struct target_backend_ops *); @@ -68,10 +69,6 @@ sense_reason_t sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops); u32 sbc_get_device_rev(struct se_device *dev); u32 sbc_get_device_type(struct se_device *dev); sector_t sbc_get_write_same_sectors(struct se_cmd *cmd); -sense_reason_t sbc_execute_unmap(struct se_cmd *cmd, - sense_reason_t (*do_unmap_fn)(struct se_cmd *cmd, void *priv, - sector_t lba, sector_t nolb), - void *priv); void sbc_dif_generate(struct se_cmd *); sense_reason_t sbc_dif_verify(struct se_cmd *, sector_t, unsigned int, unsigned int, struct scatterlist *, int); -- cgit v1.2.3-70-g09d2 From b753d643555e548163adfa2de9d75e0257e4b356 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 19 Jun 2015 15:11:00 +0200 Subject: target: implement WRITE_SAME with UNMAP bit using ->execute_unmap Signed-off-by: Christoph Hellwig Reviewed-by: Andy Grover Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_file.c | 21 --------------------- drivers/target/target_core_iblock.c | 16 ---------------- drivers/target/target_core_sbc.c | 21 +++++++++++++++++++-- include/target/target_core_backend.h | 1 - 4 files changed, 19 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index ced8c4fdc23d..f5da2c1891b5 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -518,26 +518,6 @@ fd_execute_unmap(struct se_cmd *cmd, sector_t lba, sector_t nolb) return 0; } -static sense_reason_t -fd_execute_write_same_unmap(struct se_cmd *cmd) -{ - sector_t lba = cmd->t_task_lba; - sector_t nolb = sbc_get_write_same_sectors(cmd); - sense_reason_t ret; - - if (!nolb) { - target_complete_cmd(cmd, SAM_STAT_GOOD); - return 0; - } - - ret = fd_execute_unmap(cmd, lba, nolb); - if (ret) - return ret; - - target_complete_cmd(cmd, GOOD); - return 0; -} - static sense_reason_t fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, enum dma_data_direction data_direction) @@ -827,7 +807,6 @@ static struct sbc_ops fd_sbc_ops = { .execute_rw = fd_execute_rw, .execute_sync_cache = fd_execute_sync_cache, .execute_write_same = fd_execute_write_same, - .execute_write_same_unmap = fd_execute_write_same_unmap, .execute_unmap = fd_execute_unmap, }; diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 0a2308891c81..a869022b136e 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -430,21 +430,6 @@ iblock_execute_unmap(struct se_cmd *cmd, sector_t lba, sector_t nolb) return 0; } -static sense_reason_t -iblock_execute_write_same_unmap(struct se_cmd *cmd) -{ - sector_t lba = cmd->t_task_lba; - sector_t nolb = sbc_get_write_same_sectors(cmd); - sense_reason_t ret; - - ret = iblock_execute_unmap(cmd, lba, nolb); - if (ret) - return ret; - - target_complete_cmd(cmd, GOOD); - return 0; -} - static sense_reason_t iblock_execute_write_same(struct se_cmd *cmd) { @@ -836,7 +821,6 @@ static struct sbc_ops iblock_sbc_ops = { .execute_rw = iblock_execute_rw, .execute_sync_cache = iblock_execute_sync_cache, .execute_write_same = iblock_execute_write_same, - .execute_write_same_unmap = iblock_execute_write_same_unmap, .execute_unmap = iblock_execute_unmap, }; diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index c16a66698725..9a5e7d094a5d 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -177,6 +177,23 @@ sector_t sbc_get_write_same_sectors(struct se_cmd *cmd) } EXPORT_SYMBOL(sbc_get_write_same_sectors); +static sense_reason_t +sbc_execute_write_same_unmap(struct se_cmd *cmd) +{ + struct sbc_ops *ops = cmd->protocol_data; + sector_t nolb = sbc_get_write_same_sectors(cmd); + sense_reason_t ret; + + if (nolb) { + ret = ops->execute_unmap(cmd, cmd->t_task_lba, nolb); + if (ret) + return ret; + } + + target_complete_cmd(cmd, GOOD); + return 0; +} + static sense_reason_t sbc_emulate_noop(struct se_cmd *cmd) { @@ -300,7 +317,7 @@ sbc_setup_write_same(struct se_cmd *cmd, unsigned char *flags, struct sbc_ops *o * translated into block discard requests within backend code. */ if (flags[0] & 0x08) { - if (!ops->execute_write_same_unmap) + if (!ops->execute_unmap) return TCM_UNSUPPORTED_SCSI_OPCODE; if (!dev->dev_attrib.emulate_tpws) { @@ -308,7 +325,7 @@ sbc_setup_write_same(struct se_cmd *cmd, unsigned char *flags, struct sbc_ops *o " has emulate_tpws disabled\n"); return TCM_UNSUPPORTED_SCSI_OPCODE; } - cmd->execute_cmd = ops->execute_write_same_unmap; + cmd->execute_cmd = sbc_execute_write_same_unmap; return 0; } if (!ops->execute_write_same) diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index ff399369a21a..1e5c8f949bae 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -49,7 +49,6 @@ struct sbc_ops { u32, enum dma_data_direction); sense_reason_t (*execute_sync_cache)(struct se_cmd *cmd); sense_reason_t (*execute_write_same)(struct se_cmd *cmd); - sense_reason_t (*execute_write_same_unmap)(struct se_cmd *cmd); sense_reason_t (*execute_unmap)(struct se_cmd *cmd, sector_t lba, sector_t nolb); }; -- cgit v1.2.3-70-g09d2 From ce8dd25d0ebb1d868802e1d1c770f27f2249fae4 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 19 Jun 2015 15:14:39 +0200 Subject: target: consolidate version defines Signed-off-by: Christoph Hellwig Reviewed-by: Andy Grover Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_configfs.c | 6 +++--- drivers/target/target_core_file.c | 2 +- drivers/target/target_core_iblock.c | 2 +- drivers/target/target_core_pscsi.c | 2 +- drivers/target/target_core_rd.c | 2 +- include/target/target_core_base.h | 3 +-- include/target/target_core_configfs.h | 1 - 7 files changed, 8 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 68addbc7eb7b..6003921a1c56 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -103,7 +103,7 @@ static ssize_t target_core_attr_show(struct config_item *item, char *page) { return sprintf(page, "Target Engine Core ConfigFS Infrastructure %s" - " on %s/%s on "UTS_RELEASE"\n", TARGET_CORE_CONFIGFS_VERSION, + " on %s/%s on "UTS_RELEASE"\n", TARGET_CORE_VERSION, utsname()->sysname, utsname()->machine); } @@ -3235,7 +3235,7 @@ static ssize_t target_core_hba_show_attr_hba_info( { return sprintf(page, "HBA Index: %d plugin: %s version: %s\n", hba->hba_id, hba->backend->ops->name, - TARGET_CORE_CONFIGFS_VERSION); + TARGET_CORE_VERSION); } SE_HBA_ATTR_RO(hba_info); @@ -3507,7 +3507,7 @@ static int __init target_core_init_configfs(void) goto out_global; } pr_debug("TARGET_CORE[0]: Initialized ConfigFS Fabric" - " Infrastructure: "TARGET_CORE_CONFIGFS_VERSION" on %s/%s" + " Infrastructure: "TARGET_CORE_VERSION" on %s/%s" " on "UTS_RELEASE"\n", utsname()->sysname, utsname()->machine); /* * Register built-in RAMDISK subsystem logic for virtual LUN 0 diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index f5da2c1891b5..7a0ef95b1407 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -61,7 +61,7 @@ static int fd_attach_hba(struct se_hba *hba, u32 host_id) pr_debug("CORE_HBA[%d] - TCM FILEIO HBA Driver %s on Generic" " Target Core Stack %s\n", hba->hba_id, FD_VERSION, - TARGET_CORE_MOD_VERSION); + TARGET_CORE_VERSION); pr_debug("CORE_HBA[%d] - Attached FILEIO HBA: %u to Generic\n", hba->hba_id, fd_host->fd_host_id); diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index a869022b136e..e37db742fdaf 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -57,7 +57,7 @@ static int iblock_attach_hba(struct se_hba *hba, u32 host_id) { pr_debug("CORE_HBA[%d] - TCM iBlock HBA Driver %s on" " Generic Target Core Stack %s\n", hba->hba_id, - IBLOCK_VERSION, TARGET_CORE_MOD_VERSION); + IBLOCK_VERSION, TARGET_CORE_VERSION); return 0; } diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index c673980ded04..f757178ed414 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -80,7 +80,7 @@ static int pscsi_attach_hba(struct se_hba *hba, u32 host_id) pr_debug("CORE_HBA[%d] - TCM SCSI HBA Driver %s on" " Generic Target Core Stack %s\n", hba->hba_id, - PSCSI_VERSION, TARGET_CORE_MOD_VERSION); + PSCSI_VERSION, TARGET_CORE_VERSION); pr_debug("CORE_HBA[%d] - Attached SCSI HBA to Generic\n", hba->hba_id); diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c index e98432705f39..723c97a25cbc 100644 --- a/drivers/target/target_core_rd.c +++ b/drivers/target/target_core_rd.c @@ -58,7 +58,7 @@ static int rd_attach_hba(struct se_hba *hba, u32 host_id) pr_debug("CORE_HBA[%d] - TCM Ramdisk HBA Driver %s on" " Generic Target Core Stack %s\n", hba->hba_id, - RD_HBA_VERSION, TARGET_CORE_MOD_VERSION); + RD_HBA_VERSION, TARGET_CORE_VERSION); return 0; } diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 273818403a3e..a35303302df3 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -10,8 +10,7 @@ #include #include -#define TARGET_CORE_MOD_VERSION "v4.1.0" -#define TARGET_CORE_VERSION TARGET_CORE_MOD_VERSION +#define TARGET_CORE_VERSION "v4.1.0" /* * By default we use 32-byte CDBs in TCM Core and subsystem plugin code. diff --git a/include/target/target_core_configfs.h b/include/target/target_core_configfs.h index abd063b8b301..4012ed22d783 100644 --- a/include/target/target_core_configfs.h +++ b/include/target/target_core_configfs.h @@ -1,4 +1,3 @@ -#define TARGET_CORE_CONFIGFS_VERSION TARGET_CORE_MOD_VERSION #define TARGET_CORE_CONFIG_ROOT "/sys/kernel/config" -- cgit v1.2.3-70-g09d2 From 6de2ce5b8cb6ff3562de34ea2584b0e501373f56 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 19 Jun 2015 15:14:41 +0200 Subject: target: remove target_core_configfs.h The remaining defintions are private to the target core and can be merged into target_core_internal.h. Signed-off-by: Christoph Hellwig Reviewed-by: Andy Grover Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_configfs.c | 1 - drivers/target/target_core_fabric_configfs.c | 1 - drivers/target/target_core_internal.h | 34 ++++++++++++++++++++++++++++ drivers/target/target_core_tpg.c | 1 - include/target/target_core_configfs.h | 34 ---------------------------- 5 files changed, 34 insertions(+), 37 deletions(-) delete mode 100644 include/target/target_core_configfs.h (limited to 'drivers') diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 6003921a1c56..0b0de3647478 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #include "target_core_internal.h" diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index 6cfee595f3f2..48a36989c1a6 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #include "target_core_internal.h" diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index 511178969df3..99c24acfe676 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -1,6 +1,9 @@ #ifndef TARGET_CORE_INTERNAL_H #define TARGET_CORE_INTERNAL_H +#define TARGET_CORE_NAME_MAX_LEN 64 +#define TARGET_FABRIC_NAME_SIZE 32 + struct target_backend { struct list_head list; @@ -14,6 +17,37 @@ struct target_backend { struct config_item_type tb_dev_stat_cit; }; +struct target_fabric_configfs { + atomic_t tf_access_cnt; + struct list_head tf_list; + struct config_group tf_group; + struct config_group tf_disc_group; + struct config_group *tf_default_groups[2]; + const struct target_core_fabric_ops *tf_ops; + + struct config_item_type tf_discovery_cit; + struct config_item_type tf_wwn_cit; + struct config_item_type tf_wwn_fabric_stats_cit; + struct config_item_type tf_tpg_cit; + struct config_item_type tf_tpg_base_cit; + struct config_item_type tf_tpg_lun_cit; + struct config_item_type tf_tpg_port_cit; + struct config_item_type tf_tpg_port_stat_cit; + struct config_item_type tf_tpg_np_cit; + struct config_item_type tf_tpg_np_base_cit; + struct config_item_type tf_tpg_attrib_cit; + struct config_item_type tf_tpg_auth_cit; + struct config_item_type tf_tpg_param_cit; + struct config_item_type tf_tpg_nacl_cit; + struct config_item_type tf_tpg_nacl_base_cit; + struct config_item_type tf_tpg_nacl_attrib_cit; + struct config_item_type tf_tpg_nacl_auth_cit; + struct config_item_type tf_tpg_nacl_param_cit; + struct config_item_type tf_tpg_nacl_stat_cit; + struct config_item_type tf_tpg_mappedlun_cit; + struct config_item_type tf_tpg_mappedlun_stat_cit; +}; + /* target_core_alua.c */ extern struct t10_alua_lu_gp *default_lu_gp; diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index aa39bc89227b..10321a8ffbb0 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -37,7 +37,6 @@ #include #include -#include #include #include "target_core_internal.h" diff --git a/include/target/target_core_configfs.h b/include/target/target_core_configfs.h deleted file mode 100644 index d19dbeeab930..000000000000 --- a/include/target/target_core_configfs.h +++ /dev/null @@ -1,34 +0,0 @@ - -#define TARGET_CORE_NAME_MAX_LEN 64 -#define TARGET_FABRIC_NAME_SIZE 32 - -struct target_fabric_configfs { - atomic_t tf_access_cnt; - struct list_head tf_list; - struct config_group tf_group; - struct config_group tf_disc_group; - struct config_group *tf_default_groups[2]; - const struct target_core_fabric_ops *tf_ops; - - struct config_item_type tf_discovery_cit; - struct config_item_type tf_wwn_cit; - struct config_item_type tf_wwn_fabric_stats_cit; - struct config_item_type tf_tpg_cit; - struct config_item_type tf_tpg_base_cit; - struct config_item_type tf_tpg_lun_cit; - struct config_item_type tf_tpg_port_cit; - struct config_item_type tf_tpg_port_stat_cit; - struct config_item_type tf_tpg_np_cit; - struct config_item_type tf_tpg_np_base_cit; - struct config_item_type tf_tpg_attrib_cit; - struct config_item_type tf_tpg_auth_cit; - struct config_item_type tf_tpg_param_cit; - struct config_item_type tf_tpg_nacl_cit; - struct config_item_type tf_tpg_nacl_base_cit; - struct config_item_type tf_tpg_nacl_attrib_cit; - struct config_item_type tf_tpg_nacl_auth_cit; - struct config_item_type tf_tpg_nacl_param_cit; - struct config_item_type tf_tpg_nacl_stat_cit; - struct config_item_type tf_tpg_mappedlun_cit; - struct config_item_type tf_tpg_mappedlun_stat_cit; -}; -- cgit v1.2.3-70-g09d2 From 52c1d8038594ffd82a6cf88d3dc0ca68d8179a36 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 19 Jun 2015 11:38:16 +0800 Subject: ACPICA: Linuxize: Reduce divergences for 20150616 release This patch reduces source code differences between the Linux kernel and the ACPICA upstream so that the linuxized ACPICA 20150616 release can be applied with reduced human intervention. Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/dsobject.c | 2 +- drivers/acpi/acpica/hwxfsleep.c | 2 -- drivers/acpi/acpica/rscreate.c | 2 +- drivers/acpi/acpica/rsutils.c | 2 +- drivers/acpi/acpica/tbxface.c | 1 + include/acpi/platform/acenv.h | 1 - 6 files changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/dsobject.c b/drivers/acpi/acpica/dsobject.c index 8a7b07b6adc8..4a4b2f343713 100644 --- a/drivers/acpi/acpica/dsobject.c +++ b/drivers/acpi/acpica/dsobject.c @@ -751,7 +751,7 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state, obj_desc->string.pointer = op->common.value.string; obj_desc->string.length = - (u32) ACPI_STRLEN(op->common.value.string); + (u32)ACPI_STRLEN(op->common.value.string); /* * The string is contained in the ACPI table, don't ever try diff --git a/drivers/acpi/acpica/hwxfsleep.c b/drivers/acpi/acpica/hwxfsleep.c index 3b3767698827..82e310b94ae4 100644 --- a/drivers/acpi/acpica/hwxfsleep.c +++ b/drivers/acpi/acpica/hwxfsleep.c @@ -138,7 +138,6 @@ acpi_status acpi_set_firmware_waking_vector64(u64 physical_address) { ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector64); - /* Determine if the 64-bit vector actually exists */ if ((acpi_gbl_FACS->length <= 32) || (acpi_gbl_FACS->version < 1)) { @@ -154,7 +153,6 @@ acpi_status acpi_set_firmware_waking_vector64(u64 physical_address) ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector64) #endif - /******************************************************************************* * * FUNCTION: acpi_enter_sleep_state_s4bios diff --git a/drivers/acpi/acpica/rscreate.c b/drivers/acpi/acpica/rscreate.c index 15434e4c9b34..f30f35e6ff2a 100644 --- a/drivers/acpi/acpica/rscreate.c +++ b/drivers/acpi/acpica/rscreate.c @@ -353,7 +353,7 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object, /* +1 to include null terminator */ user_prt->length += - (u32) ACPI_STRLEN(user_prt->source) + 1; + (u32)ACPI_STRLEN(user_prt->source) + 1; break; case ACPI_TYPE_STRING: diff --git a/drivers/acpi/acpica/rsutils.c b/drivers/acpi/acpica/rsutils.c index ece3cd60cc6a..90417de38dab 100644 --- a/drivers/acpi/acpica/rsutils.c +++ b/drivers/acpi/acpica/rsutils.c @@ -367,7 +367,7 @@ acpi_rs_get_resource_source(acpi_rs_length resource_length, (u32) ACPI_STRLEN(ACPI_CAST_PTR(char, &aml_resource_source[1])) + 1; - total_length = (u32) ACPI_ROUND_UP_TO_NATIVE_WORD(total_length); + total_length = (u32)ACPI_ROUND_UP_TO_NATIVE_WORD(total_length); ACPI_MEMSET(resource_source->string_ptr, 0, total_length); diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c index 60e94f87f27a..54b9f7957ff1 100644 --- a/drivers/acpi/acpica/tbxface.c +++ b/drivers/acpi/acpica/tbxface.c @@ -242,6 +242,7 @@ acpi_get_table_header(char *signature, if (!header) { return (AE_NO_MEMORY); } + ACPI_MEMCPY(out_table_header, header, sizeof(struct acpi_table_header)); acpi_os_unmap_memory(header, diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h index 073997d729e9..1e84e62b448d 100644 --- a/include/acpi/platform/acenv.h +++ b/include/acpi/platform/acenv.h @@ -359,7 +359,6 @@ #define ACPI_MEMCMP(s1,s2,n) memcmp((const char *)(s1), (const char *)(s2), (acpi_size)(n)) #define ACPI_MEMCPY(d,s,n) (void) memcpy((d), (s), (acpi_size)(n)) #define ACPI_MEMSET(d,s,n) (void) memset((d), (s), (acpi_size)(n)) - #define ACPI_TOUPPER(i) toupper((int) (i)) #define ACPI_TOLOWER(i) tolower((int) (i)) #define ACPI_IS_XDIGIT(i) isxdigit((int) (i)) -- cgit v1.2.3-70-g09d2 From 9bf39ab2adafd7cf8740859cb49e7b7952813a5d Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Fri, 19 Jun 2015 10:29:13 +0200 Subject: vfs: add file_path() helper Turn d_path(&file->f_path, ...); into file_path(file, ...); Signed-off-by: Miklos Szeredi Signed-off-by: Al Viro --- arch/arc/kernel/troubleshoot.c | 10 +++------- arch/blackfin/kernel/trace.c | 2 +- arch/tile/kernel/stack.c | 2 +- arch/tile/mm/elf.c | 2 +- drivers/block/loop.c | 2 +- drivers/md/bitmap.c | 2 +- drivers/md/md.c | 2 +- drivers/usb/gadget/function/f_mass_storage.c | 2 +- drivers/usb/gadget/function/storage_common.c | 2 +- fs/binfmt_elf.c | 4 ++-- fs/coredump.c | 2 +- fs/ext4/super.c | 2 +- fs/open.c | 6 ++++++ include/linux/fs.h | 2 ++ kernel/events/core.c | 2 +- mm/memory.c | 2 +- 16 files changed, 25 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/arch/arc/kernel/troubleshoot.c b/arch/arc/kernel/troubleshoot.c index e00a01879025..9f80c5adcb68 100644 --- a/arch/arc/kernel/troubleshoot.c +++ b/arch/arc/kernel/troubleshoot.c @@ -67,15 +67,12 @@ static void print_task_path_n_nm(struct task_struct *tsk, char *buf) mmput(mm); if (exe_file) { - path = exe_file->f_path; - path_get(&exe_file->f_path); + path_nm = file_path(exe_file, buf, 255); fput(exe_file); - path_nm = d_path(&path, buf, 255); - path_put(&path); } done: - pr_info("Path: %s\n", path_nm); + pr_info("Path: %s\n", !IS_ERR(path_nm) ? path_nm : "?"); } static void show_faulting_vma(unsigned long address, char *buf) @@ -99,8 +96,7 @@ static void show_faulting_vma(unsigned long address, char *buf) if (vma && (vma->vm_start <= address)) { struct file *file = vma->vm_file; if (file) { - struct path *path = &file->f_path; - nm = d_path(path, buf, PAGE_SIZE - 1); + nm = file_path(file, buf, PAGE_SIZE - 1); inode = file_inode(vma->vm_file); dev = inode->i_sb->s_dev; ino = inode->i_ino; diff --git a/arch/blackfin/kernel/trace.c b/arch/blackfin/kernel/trace.c index c36efa0c7163..719dd796c12c 100644 --- a/arch/blackfin/kernel/trace.c +++ b/arch/blackfin/kernel/trace.c @@ -136,7 +136,7 @@ void decode_address(char *buf, unsigned long address) struct file *file = vma->vm_file; if (file) { - char *d_name = d_path(&file->f_path, _tmpbuf, + char *d_name = file_path(file, _tmpbuf, sizeof(_tmpbuf)); if (!IS_ERR(d_name)) name = d_name; diff --git a/arch/tile/kernel/stack.c b/arch/tile/kernel/stack.c index c42dce50acd8..8d62cf12c2c0 100644 --- a/arch/tile/kernel/stack.c +++ b/arch/tile/kernel/stack.c @@ -334,7 +334,7 @@ static void describe_addr(struct KBacktraceIterator *kbt, } if (vma->vm_file) { - p = d_path(&vma->vm_file->f_path, buf, bufsize); + p = file_path(vma->vm_file, buf, bufsize); if (IS_ERR(p)) p = "?"; name = kbasename(p); diff --git a/arch/tile/mm/elf.c b/arch/tile/mm/elf.c index f7ddae3725a4..6225cc998db1 100644 --- a/arch/tile/mm/elf.c +++ b/arch/tile/mm/elf.c @@ -56,7 +56,7 @@ static int notify_exec(struct mm_struct *mm) if (exe_file == NULL) goto done_free; - path = d_path(&exe_file->f_path, buf, PAGE_SIZE); + path = file_path(exe_file, buf, PAGE_SIZE); if (IS_ERR(path)) goto done_put; diff --git a/drivers/block/loop.c b/drivers/block/loop.c index d7173cb1ea76..0d8ad59413cd 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -568,7 +568,7 @@ static ssize_t loop_attr_backing_file_show(struct loop_device *lo, char *buf) spin_lock_irq(&lo->lo_lock); if (lo->lo_backing_file) - p = d_path(&lo->lo_backing_file->f_path, buf, PAGE_SIZE - 1); + p = file_path(lo->lo_backing_file, buf, PAGE_SIZE - 1); spin_unlock_irq(&lo->lo_lock); if (IS_ERR_OR_NULL(p)) diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 2bc56e2a3526..dda33d648354 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -834,7 +834,7 @@ static void bitmap_file_kick(struct bitmap *bitmap) if (bitmap->storage.file) { path = kmalloc(PAGE_SIZE, GFP_KERNEL); if (path) - ptr = d_path(&bitmap->storage.file->f_path, + ptr = file_path(bitmap->storage.file, path, PAGE_SIZE); printk(KERN_ALERT diff --git a/drivers/md/md.c b/drivers/md/md.c index 593a02476c78..e67f3ac137bf 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -5741,7 +5741,7 @@ static int get_bitmap_file(struct mddev *mddev, void __user * arg) /* bitmap disabled, zero the first byte and copy out */ if (!mddev->bitmap_info.file) file->pathname[0] = '\0'; - else if ((ptr = d_path(&mddev->bitmap_info.file->f_path, + else if ((ptr = file_path(mddev->bitmap_info.file, file->pathname, sizeof(file->pathname))), IS_ERR(ptr)) err = PTR_ERR(ptr); diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index 3cc109f3c9c8..d2259c663996 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -2936,7 +2936,7 @@ int fsg_common_create_lun(struct fsg_common *common, struct fsg_lun_config *cfg, if (fsg_lun_is_open(lun)) { p = "(error)"; if (pathbuf) { - p = d_path(&lun->filp->f_path, pathbuf, PATH_MAX); + p = file_path(lun->filp, pathbuf, PATH_MAX); if (IS_ERR(p)) p = "(error)"; } diff --git a/drivers/usb/gadget/function/storage_common.c b/drivers/usb/gadget/function/storage_common.c index 648f9e489b39..d62683017cf3 100644 --- a/drivers/usb/gadget/function/storage_common.c +++ b/drivers/usb/gadget/function/storage_common.c @@ -341,7 +341,7 @@ ssize_t fsg_show_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, down_read(filesem); if (fsg_lun_is_open(curlun)) { /* Get the complete pathname */ - p = d_path(&curlun->filp->f_path, buf, PAGE_SIZE - 1); + p = file_path(curlun->filp, buf, PAGE_SIZE - 1); if (IS_ERR(p)) rc = PTR_ERR(p); else { diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 241ef68d2893..5046b6247103 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -1530,7 +1530,7 @@ static int fill_files_note(struct memelfnote *note) file = vma->vm_file; if (!file) continue; - filename = d_path(&file->f_path, name_curpos, remaining); + filename = file_path(file, name_curpos, remaining); if (IS_ERR(filename)) { if (PTR_ERR(filename) == -ENAMETOOLONG) { vfree(data); @@ -1540,7 +1540,7 @@ static int fill_files_note(struct memelfnote *note) continue; } - /* d_path() fills at the end, move name down */ + /* file_path() fills at the end, move name down */ /* n = strlen(filename) + 1: */ n = (name_curpos + remaining) - filename; remaining = filename - name_curpos; diff --git a/fs/coredump.c b/fs/coredump.c index bbbe139ab280..5b771b36cc6e 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -138,7 +138,7 @@ static int cn_print_exe_file(struct core_name *cn) goto put_exe_file; } - path = d_path(&exe_file->f_path, pathbuf, PATH_MAX); + path = file_path(exe_file, pathbuf, PATH_MAX); if (IS_ERR(path)) { ret = PTR_ERR(path); goto free_buf; diff --git a/fs/ext4/super.c b/fs/ext4/super.c index f06d0589ddba..0ae853d2e1f1 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -449,7 +449,7 @@ void __ext4_error_file(struct file *file, const char *function, es = EXT4_SB(inode->i_sb)->s_es; es->s_last_error_ino = cpu_to_le32(inode->i_ino); if (ext4_error_ratelimit(inode->i_sb)) { - path = d_path(&(file->f_path), pathname, sizeof(pathname)); + path = file_path(file, pathname, sizeof(pathname)); if (IS_ERR(path)) path = "(unknown)"; va_start(args, fmt); diff --git a/fs/open.c b/fs/open.c index b1c5823b7f11..1dbc79358d59 100644 --- a/fs/open.c +++ b/fs/open.c @@ -823,6 +823,12 @@ int finish_no_open(struct file *file, struct dentry *dentry) } EXPORT_SYMBOL(finish_no_open); +char *file_path(struct file *filp, char *buf, int buflen) +{ + return d_path(&filp->f_path, buf, buflen); +} +EXPORT_SYMBOL(file_path); + /** * vfs_open - open the file at the given path * @path: path to open diff --git a/include/linux/fs.h b/include/linux/fs.h index 2bd77e10e8e5..2c135ad741a9 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2500,6 +2500,8 @@ extern struct file * open_exec(const char *); extern int is_subdir(struct dentry *, struct dentry *); extern int path_is_under(struct path *, struct path *); +extern char *file_path(struct file *, char *, int); + #include /* needed for stackable file system support */ diff --git a/kernel/events/core.c b/kernel/events/core.c index 81aa3a4ece9f..5c964e845483 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -5791,7 +5791,7 @@ static void perf_event_mmap_event(struct perf_mmap_event *mmap_event) * need to add enough zero bytes after the string to handle * the 64bit alignment we do later. */ - name = d_path(&file->f_path, buf, PATH_MAX - sizeof(u64)); + name = file_path(file, buf, PATH_MAX - sizeof(u64)); if (IS_ERR(name)) { name = "//toolong"; goto cpy_name; diff --git a/mm/memory.c b/mm/memory.c index 22e037e3364e..28c10da1efbc 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -3724,7 +3724,7 @@ void print_vma_addr(char *prefix, unsigned long ip) if (buf) { char *p; - p = d_path(&f->f_path, buf, PAGE_SIZE); + p = file_path(f, buf, PAGE_SIZE); if (IS_ERR(p)) p = "?"; printk("%s%s[%lx+%lx]", prefix, kbasename(p), -- cgit v1.2.3-70-g09d2 From 2726d56620ce71f40dd583d51391b86e1ab8cc57 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Fri, 19 Jun 2015 10:30:28 +0200 Subject: vfs: add seq_file_path() helper Turn seq_path(..., &file->f_path, ...); into seq_file_path(..., file, ...); Signed-off-by: Miklos Szeredi Signed-off-by: Al Viro --- drivers/md/bitmap.c | 2 +- fs/proc/nommu.c | 2 +- fs/proc/task_mmu.c | 4 ++-- fs/proc/task_nommu.c | 2 +- fs/seq_file.c | 14 ++++++++++++++ include/linux/seq_file.h | 1 + mm/swapfile.c | 2 +- 7 files changed, 21 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index dda33d648354..3813fdfee4be 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -1922,7 +1922,7 @@ void bitmap_status(struct seq_file *seq, struct bitmap *bitmap) chunk_kb ? "KB" : "B"); if (bitmap->storage.file) { seq_printf(seq, ", file: "); - seq_path(seq, &bitmap->storage.file->f_path, " \t\n"); + seq_file_path(seq, bitmap->storage.file, " \t\n"); } seq_printf(seq, "\n"); diff --git a/fs/proc/nommu.c b/fs/proc/nommu.c index d4a35746cab9..f8595e8b5cd0 100644 --- a/fs/proc/nommu.c +++ b/fs/proc/nommu.c @@ -64,7 +64,7 @@ static int nommu_region_show(struct seq_file *m, struct vm_region *region) if (file) { seq_pad(m, ' '); - seq_path(m, &file->f_path, ""); + seq_file_path(m, file, ""); } seq_putc(m, '\n'); diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 6dee68d013ff..ca1e091881d4 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -310,7 +310,7 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid) */ if (file) { seq_pad(m, ' '); - seq_path(m, &file->f_path, "\n"); + seq_file_path(m, file, "\n"); goto done; } @@ -1509,7 +1509,7 @@ static int show_numa_map(struct seq_file *m, void *v, int is_pid) if (file) { seq_puts(m, " file="); - seq_path(m, &file->f_path, "\n\t= "); + seq_file_path(m, file, "\n\t= "); } else if (vma->vm_start <= mm->brk && vma->vm_end >= mm->start_brk) { seq_puts(m, " heap"); } else { diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c index 599ec2e20104..e0d64c92e4f6 100644 --- a/fs/proc/task_nommu.c +++ b/fs/proc/task_nommu.c @@ -180,7 +180,7 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma, if (file) { seq_pad(m, ' '); - seq_path(m, &file->f_path, ""); + seq_file_path(m, file, ""); } else if (mm) { pid_t tid = pid_of_stack(priv, vma, is_pid); diff --git a/fs/seq_file.c b/fs/seq_file.c index 555f82155be8..d8a0545ad7ea 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c @@ -487,6 +487,20 @@ int seq_path(struct seq_file *m, const struct path *path, const char *esc) } EXPORT_SYMBOL(seq_path); +/** + * seq_file_path - seq_file interface to print a pathname of a file + * @m: the seq_file handle + * @file: the struct file to print + * @esc: set of characters to escape in the output + * + * return the absolute path to the file. + */ +int seq_file_path(struct seq_file *m, struct file *file, const char *esc) +{ + return seq_path(m, &file->f_path, esc); +} +EXPORT_SYMBOL(seq_file_path); + /* * Same as seq_path, but relative to supplied root. */ diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h index afbb1fd77c77..912a7c482649 100644 --- a/include/linux/seq_file.h +++ b/include/linux/seq_file.h @@ -123,6 +123,7 @@ __printf(2, 3) int seq_printf(struct seq_file *, const char *, ...); __printf(2, 0) int seq_vprintf(struct seq_file *, const char *, va_list args); int seq_path(struct seq_file *, const struct path *, const char *); +int seq_file_path(struct seq_file *, struct file *, const char *); int seq_dentry(struct seq_file *, struct dentry *, const char *); int seq_path_root(struct seq_file *m, const struct path *path, const struct path *root, const char *esc); diff --git a/mm/swapfile.c b/mm/swapfile.c index a7e72103f23b..41e4581af7c5 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -2032,7 +2032,7 @@ static int swap_show(struct seq_file *swap, void *v) } file = si->swap_file; - len = seq_path(swap, &file->f_path, " \t\n\\"); + len = seq_file_path(swap, file, " \t\n\\"); seq_printf(swap, "%*s%s\t%u\t%u\t%d\n", len < 40 ? 40 - len : 1, " ", S_ISBLK(file_inode(file)->i_mode) ? -- cgit v1.2.3-70-g09d2 From dc3f4198eac14e52a98dfc79cd84b45e280f59cd Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 18 May 2015 10:10:34 -0400 Subject: make simple_positive() public Signed-off-by: Al Viro --- arch/powerpc/platforms/cell/spufs/inode.c | 2 +- arch/s390/hypfs/inode.c | 7 +------ drivers/block/drbd/drbd_debugfs.c | 10 +--------- drivers/infiniband/hw/ipath/ipath_fs.c | 2 +- drivers/infiniband/hw/qib/qib_fs.c | 2 +- fs/autofs4/autofs_i.h | 5 ----- fs/ceph/dir.c | 2 +- fs/configfs/inode.c | 2 +- fs/debugfs/inode.c | 11 +++-------- fs/libfs.c | 5 ----- fs/nfs/dir.c | 2 +- fs/tracefs/inode.c | 11 +++-------- include/linux/dcache.h | 5 +++++ security/inode.c | 19 ++++++------------- 14 files changed, 25 insertions(+), 60 deletions(-) (limited to 'drivers') diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index 1ba6307be4db..11634fa7ab3c 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -166,7 +166,7 @@ static void spufs_prune_dir(struct dentry *dir) mutex_lock(&d_inode(dir)->i_mutex); list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_child) { spin_lock(&dentry->d_lock); - if (!(d_unhashed(dentry)) && d_really_is_positive(dentry)) { + if (simple_positive(dentry)) { dget_dlock(dentry); __d_drop(dentry); spin_unlock(&dentry->d_lock); diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c index d3f896a35b98..8ffad5437232 100644 --- a/arch/s390/hypfs/inode.c +++ b/arch/s390/hypfs/inode.c @@ -62,18 +62,13 @@ static void hypfs_add_dentry(struct dentry *dentry) hypfs_last_dentry = dentry; } -static inline int hypfs_positive(struct dentry *dentry) -{ - return d_really_is_positive(dentry) && !d_unhashed(dentry); -} - static void hypfs_remove(struct dentry *dentry) { struct dentry *parent; parent = dentry->d_parent; mutex_lock(&d_inode(parent)->i_mutex); - if (hypfs_positive(dentry)) { + if (simple_positive(dentry)) { if (d_is_dir(dentry)) simple_rmdir(d_inode(parent), dentry); else diff --git a/drivers/block/drbd/drbd_debugfs.c b/drivers/block/drbd/drbd_debugfs.c index a6ee3d750c30..6b88a35fb048 100644 --- a/drivers/block/drbd/drbd_debugfs.c +++ b/drivers/block/drbd/drbd_debugfs.c @@ -419,14 +419,6 @@ static int in_flight_summary_show(struct seq_file *m, void *pos) return 0; } -/* simple_positive(file->f_path.dentry) respectively debugfs_positive(), - * but neither is "reachable" from here. - * So we have our own inline version of it above. :-( */ -static inline int debugfs_positive(struct dentry *dentry) -{ - return d_really_is_positive(dentry) && !d_unhashed(dentry); -} - /* make sure at *open* time that the respective object won't go away. */ static int drbd_single_open(struct file *file, int (*show)(struct seq_file *, void *), void *data, struct kref *kref, @@ -444,7 +436,7 @@ static int drbd_single_open(struct file *file, int (*show)(struct seq_file *, vo /* serialize with d_delete() */ mutex_lock(&d_inode(parent)->i_mutex); /* Make sure the object is still alive */ - if (debugfs_positive(file->f_path.dentry) + if (simple_positive(file->f_path.dentry) && kref_get_unless_zero(kref)) ret = 0; mutex_unlock(&d_inode(parent)->i_mutex); diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c index 1ca8e32a9592..25422a3a7238 100644 --- a/drivers/infiniband/hw/ipath/ipath_fs.c +++ b/drivers/infiniband/hw/ipath/ipath_fs.c @@ -277,7 +277,7 @@ static int remove_file(struct dentry *parent, char *name) } spin_lock(&tmp->d_lock); - if (!d_unhashed(tmp) && d_really_is_positive(tmp)) { + if (simple_positive(tmp)) { dget_dlock(tmp); __d_drop(tmp); spin_unlock(&tmp->d_lock); diff --git a/drivers/infiniband/hw/qib/qib_fs.c b/drivers/infiniband/hw/qib/qib_fs.c index bdd5d3857203..13ef22bd9459 100644 --- a/drivers/infiniband/hw/qib/qib_fs.c +++ b/drivers/infiniband/hw/qib/qib_fs.c @@ -455,7 +455,7 @@ static int remove_file(struct dentry *parent, char *name) } spin_lock(&tmp->d_lock); - if (!d_unhashed(tmp) && d_really_is_positive(tmp)) { + if (simple_positive(tmp)) { __d_drop(tmp); spin_unlock(&tmp->d_lock); simple_unlink(d_inode(parent), tmp); diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h index 5b700ef1e59d..c37149b929be 100644 --- a/fs/autofs4/autofs_i.h +++ b/fs/autofs4/autofs_i.h @@ -238,11 +238,6 @@ static inline u64 autofs4_get_ino(struct autofs_sb_info *sbi) return d_inode(sbi->sb->s_root)->i_ino; } -static inline int simple_positive(struct dentry *dentry) -{ - return d_really_is_positive(dentry) && !d_unhashed(dentry); -} - static inline void __autofs4_add_expiring(struct dentry *dentry) { struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 4248307fea90..edbb8da02a6a 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -161,7 +161,7 @@ more: } spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); if (di->lease_shared_gen == shared_gen && - !d_unhashed(dentry) && d_really_is_positive(dentry) && + simple_positive(dentry) && ceph_snap(d_inode(dentry)) != CEPH_SNAPDIR && ceph_ino(d_inode(dentry)) != CEPH_INO_CEPH && fpos_cmp(ctx->pos, di->offset) <= 0) diff --git a/fs/configfs/inode.c b/fs/configfs/inode.c index 8d89f5fd0331..eae87575e681 100644 --- a/fs/configfs/inode.c +++ b/fs/configfs/inode.c @@ -236,7 +236,7 @@ void configfs_drop_dentry(struct configfs_dirent * sd, struct dentry * parent) if (dentry) { spin_lock(&dentry->d_lock); - if (!d_unhashed(dentry) && d_really_is_positive(dentry)) { + if (simple_positive(dentry)) { dget_dlock(dentry); __d_drop(dentry); spin_unlock(&dentry->d_lock); diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 7eaec88ea970..ef86ad6bdc3e 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -44,11 +44,6 @@ static struct inode *debugfs_get_inode(struct super_block *sb) return inode; } -static inline int debugfs_positive(struct dentry *dentry) -{ - return d_really_is_positive(dentry) && !d_unhashed(dentry); -} - struct debugfs_mount_opts { kuid_t uid; kgid_t gid; @@ -522,7 +517,7 @@ static int __debugfs_remove(struct dentry *dentry, struct dentry *parent) { int ret = 0; - if (debugfs_positive(dentry)) { + if (simple_positive(dentry)) { dget(dentry); if (d_is_dir(dentry)) ret = simple_rmdir(d_inode(parent), dentry); @@ -602,7 +597,7 @@ void debugfs_remove_recursive(struct dentry *dentry) */ spin_lock(&parent->d_lock); list_for_each_entry(child, &parent->d_subdirs, d_child) { - if (!debugfs_positive(child)) + if (!simple_positive(child)) continue; /* perhaps simple_empty(child) makes more sense */ @@ -623,7 +618,7 @@ void debugfs_remove_recursive(struct dentry *dentry) * from d_subdirs. When releasing the parent->d_lock we can * no longer trust that the next pointer is valid. * Restart the loop. We'll skip this one with the - * debugfs_positive() check. + * simple_positive() check. */ goto loop; } diff --git a/fs/libfs.c b/fs/libfs.c index 65e1feca8b98..4d9e6c118fe1 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -20,11 +20,6 @@ #include "internal.h" -static inline int simple_positive(struct dentry *dentry) -{ - return d_really_is_positive(dentry) && !d_unhashed(dentry); -} - int simple_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index b2c8b31b2be7..b9108f4254a7 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1771,7 +1771,7 @@ EXPORT_SYMBOL_GPL(nfs_mkdir); static void nfs_dentry_handle_enoent(struct dentry *dentry) { - if (d_really_is_positive(dentry) && !d_unhashed(dentry)) + if (simple_positive(dentry)) d_delete(dentry); } diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c index d92bdf3b079a..6e8a1400d662 100644 --- a/fs/tracefs/inode.c +++ b/fs/tracefs/inode.c @@ -496,16 +496,11 @@ struct dentry *tracefs_create_instance_dir(const char *name, struct dentry *pare return dentry; } -static inline int tracefs_positive(struct dentry *dentry) -{ - return dentry->d_inode && !d_unhashed(dentry); -} - static int __tracefs_remove(struct dentry *dentry, struct dentry *parent) { int ret = 0; - if (tracefs_positive(dentry)) { + if (simple_positive(dentry)) { if (dentry->d_inode) { dget(dentry); switch (dentry->d_inode->i_mode & S_IFMT) { @@ -582,7 +577,7 @@ void tracefs_remove_recursive(struct dentry *dentry) */ spin_lock(&parent->d_lock); list_for_each_entry(child, &parent->d_subdirs, d_child) { - if (!tracefs_positive(child)) + if (!simple_positive(child)) continue; /* perhaps simple_empty(child) makes more sense */ @@ -603,7 +598,7 @@ void tracefs_remove_recursive(struct dentry *dentry) * from d_subdirs. When releasing the parent->d_lock we can * no longer trust that the next pointer is valid. * Restart the loop. We'll skip this one with the - * tracefs_positive() check. + * simple_positive() check. */ goto loop; } diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 167ec0934049..d2d50249b7b2 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -507,6 +507,11 @@ static inline bool d_really_is_positive(const struct dentry *dentry) return dentry->d_inode != NULL; } +static inline int simple_positive(struct dentry *dentry) +{ + return d_really_is_positive(dentry) && !d_unhashed(dentry); +} + extern void d_set_fallthru(struct dentry *dentry); static inline bool d_is_fallthru(const struct dentry *dentry) diff --git a/security/inode.c b/security/inode.c index 91503b79c5f8..6df0d8dae1e0 100644 --- a/security/inode.c +++ b/security/inode.c @@ -25,11 +25,6 @@ static struct vfsmount *mount; static int mount_count; -static inline int positive(struct dentry *dentry) -{ - return d_really_is_positive(dentry) && !d_unhashed(dentry); -} - static int fill_super(struct super_block *sb, void *data, int silent) { static struct tree_descr files[] = {{""}}; @@ -201,14 +196,12 @@ void securityfs_remove(struct dentry *dentry) return; mutex_lock(&d_inode(parent)->i_mutex); - if (positive(dentry)) { - if (d_really_is_positive(dentry)) { - if (d_is_dir(dentry)) - simple_rmdir(d_inode(parent), dentry); - else - simple_unlink(d_inode(parent), dentry); - dput(dentry); - } + if (simple_positive(dentry)) { + if (d_is_dir(dentry)) + simple_rmdir(d_inode(parent), dentry); + else + simple_unlink(d_inode(parent), dentry); + dput(dentry); } mutex_unlock(&d_inode(parent)->i_mutex); simple_release_fs(&mount, &mount_count); -- cgit v1.2.3-70-g09d2 From 59a5b0f7bf74f88da6670bcbf924d8cc1e75b1ee Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 24 Jun 2015 07:54:15 +0200 Subject: virtio-pci: alloc only resources actually used. Move resource allocation from common code to legacy and modern code. Only request resources actually used, i.e. bar0 in legacy mode and the bar(s) specified by capabilities in modern mode. Signed-off-by: Gerd Hoffmann Signed-off-by: Michael S. Tsirkin --- drivers/virtio/virtio_pci_common.c | 7 ------- drivers/virtio/virtio_pci_common.h | 2 ++ drivers/virtio/virtio_pci_legacy.c | 13 ++++++++++++- drivers/virtio/virtio_pci_modern.c | 24 ++++++++++++++++++------ 4 files changed, 32 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/virtio/virtio_pci_common.c b/drivers/virtio/virtio_pci_common.c index e894eb278d83..4fd036c3468f 100644 --- a/drivers/virtio/virtio_pci_common.c +++ b/drivers/virtio/virtio_pci_common.c @@ -509,10 +509,6 @@ static int virtio_pci_probe(struct pci_dev *pci_dev, if (rc) goto err_enable_device; - rc = pci_request_regions(pci_dev, "virtio-pci"); - if (rc) - goto err_request_regions; - if (force_legacy) { rc = virtio_pci_legacy_probe(vp_dev); /* Also try modern mode if we can't map BAR0 (no IO space). */ @@ -542,8 +538,6 @@ err_register: else virtio_pci_modern_remove(vp_dev); err_probe: - pci_release_regions(pci_dev); -err_request_regions: pci_disable_device(pci_dev); err_enable_device: kfree(vp_dev); @@ -561,7 +555,6 @@ static void virtio_pci_remove(struct pci_dev *pci_dev) else virtio_pci_modern_remove(vp_dev); - pci_release_regions(pci_dev); pci_disable_device(pci_dev); } diff --git a/drivers/virtio/virtio_pci_common.h b/drivers/virtio/virtio_pci_common.h index 28ee4e56badf..b976d968e793 100644 --- a/drivers/virtio/virtio_pci_common.h +++ b/drivers/virtio/virtio_pci_common.h @@ -75,6 +75,8 @@ struct virtio_pci_device { /* Multiply queue_notify_off by this value. (non-legacy mode). */ u32 notify_offset_multiplier; + int modern_bars; + /* Legacy only field */ /* the IO mapping for the PCI config space */ void __iomem *ioaddr; diff --git a/drivers/virtio/virtio_pci_legacy.c b/drivers/virtio/virtio_pci_legacy.c index 256a5278a515..48bc9797e530 100644 --- a/drivers/virtio/virtio_pci_legacy.c +++ b/drivers/virtio/virtio_pci_legacy.c @@ -215,6 +215,7 @@ static const struct virtio_config_ops virtio_pci_config_ops = { int virtio_pci_legacy_probe(struct virtio_pci_device *vp_dev) { struct pci_dev *pci_dev = vp_dev->pci_dev; + int rc; /* We only own devices >= 0x1000 and <= 0x103f: leave the rest. */ if (pci_dev->device < 0x1000 || pci_dev->device > 0x103f) @@ -226,9 +227,14 @@ int virtio_pci_legacy_probe(struct virtio_pci_device *vp_dev) return -ENODEV; } + rc = pci_request_region(pci_dev, 0, "virtio-pci-legacy"); + if (rc) + return rc; + + rc = -ENOMEM; vp_dev->ioaddr = pci_iomap(pci_dev, 0, 0); if (!vp_dev->ioaddr) - return -ENOMEM; + goto err_iomap; vp_dev->isr = vp_dev->ioaddr + VIRTIO_PCI_ISR; @@ -246,6 +252,10 @@ int virtio_pci_legacy_probe(struct virtio_pci_device *vp_dev) vp_dev->del_vq = del_vq; return 0; + +err_iomap: + pci_release_region(pci_dev, 0); + return rc; } void virtio_pci_legacy_remove(struct virtio_pci_device *vp_dev) @@ -253,4 +263,5 @@ void virtio_pci_legacy_remove(struct virtio_pci_device *vp_dev) struct pci_dev *pci_dev = vp_dev->pci_dev; pci_iounmap(pci_dev, vp_dev->ioaddr); + pci_release_region(pci_dev, 0); } diff --git a/drivers/virtio/virtio_pci_modern.c b/drivers/virtio/virtio_pci_modern.c index e88e0997a889..8e5cf194cc0b 100644 --- a/drivers/virtio/virtio_pci_modern.c +++ b/drivers/virtio/virtio_pci_modern.c @@ -499,7 +499,7 @@ static const struct virtio_config_ops virtio_pci_config_ops = { * Returns offset of the capability, or 0. */ static inline int virtio_pci_find_capability(struct pci_dev *dev, u8 cfg_type, - u32 ioresource_types) + u32 ioresource_types, int *bars) { int pos; @@ -520,8 +520,10 @@ static inline int virtio_pci_find_capability(struct pci_dev *dev, u8 cfg_type, if (type == cfg_type) { if (pci_resource_len(dev, bar) && - pci_resource_flags(dev, bar) & ioresource_types) + pci_resource_flags(dev, bar) & ioresource_types) { + *bars |= (1 << bar); return pos; + } } } return 0; @@ -617,7 +619,8 @@ int virtio_pci_modern_probe(struct virtio_pci_device *vp_dev) /* check for a common config: if not, use legacy mode (bar 0). */ common = virtio_pci_find_capability(pci_dev, VIRTIO_PCI_CAP_COMMON_CFG, - IORESOURCE_IO | IORESOURCE_MEM); + IORESOURCE_IO | IORESOURCE_MEM, + &vp_dev->modern_bars); if (!common) { dev_info(&pci_dev->dev, "virtio_pci: leaving for legacy driver\n"); @@ -626,9 +629,11 @@ int virtio_pci_modern_probe(struct virtio_pci_device *vp_dev) /* If common is there, these should be too... */ isr = virtio_pci_find_capability(pci_dev, VIRTIO_PCI_CAP_ISR_CFG, - IORESOURCE_IO | IORESOURCE_MEM); + IORESOURCE_IO | IORESOURCE_MEM, + &vp_dev->modern_bars); notify = virtio_pci_find_capability(pci_dev, VIRTIO_PCI_CAP_NOTIFY_CFG, - IORESOURCE_IO | IORESOURCE_MEM); + IORESOURCE_IO | IORESOURCE_MEM, + &vp_dev->modern_bars); if (!isr || !notify) { dev_err(&pci_dev->dev, "virtio_pci: missing capabilities %i/%i/%i\n", @@ -640,7 +645,13 @@ int virtio_pci_modern_probe(struct virtio_pci_device *vp_dev) * device-specific configuration. */ device = virtio_pci_find_capability(pci_dev, VIRTIO_PCI_CAP_DEVICE_CFG, - IORESOURCE_IO | IORESOURCE_MEM); + IORESOURCE_IO | IORESOURCE_MEM, + &vp_dev->modern_bars); + + err = pci_request_selected_regions(pci_dev, vp_dev->modern_bars, + "virtio-pci-modern"); + if (err) + return err; err = -EINVAL; vp_dev->common = map_capability(pci_dev, common, @@ -727,4 +738,5 @@ void virtio_pci_modern_remove(struct virtio_pci_device *vp_dev) pci_iounmap(pci_dev, vp_dev->notify_base); pci_iounmap(pci_dev, vp_dev->isr); pci_iounmap(pci_dev, vp_dev->common); + pci_release_selected_regions(pci_dev, vp_dev->modern_bars); } -- cgit v1.2.3-70-g09d2 From a903e3b64adfc2e126237f06e0b3ea7d2d8d13b5 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Tue, 17 Mar 2015 15:31:11 +0200 Subject: drm/omap: return error if dma_alloc_writecombine fails On a platform with no TILER (e.g. omap3, am43xx), when the user wants to allocate buffer with flag OMAP_BO_SCANOUT, the buffer needs to be allocated with dma_alloc_writecombine. For some reason the driver does not return an error if that alloc fails, instead it continues without backing memory. This leads to errors later when the user tries to use the buffer. This patch makes the driver return an error if dma_alloc_writecombine fails. Signed-off-by: Tomi Valkeinen Acked-by: Laurent Pinchart --- drivers/gpu/drm/omapdrm/omap_gem.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c index 2ab77801cf5f..874eb6dcf94b 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.c +++ b/drivers/gpu/drm/omapdrm/omap_gem.c @@ -1378,11 +1378,7 @@ struct drm_gem_object *omap_gem_new(struct drm_device *dev, omap_obj = kzalloc(sizeof(*omap_obj), GFP_KERNEL); if (!omap_obj) - goto fail; - - spin_lock(&priv->list_lock); - list_add(&omap_obj->mm_list, &priv->obj_list); - spin_unlock(&priv->list_lock); + return NULL; obj = &omap_obj->base; @@ -1392,11 +1388,19 @@ struct drm_gem_object *omap_gem_new(struct drm_device *dev, */ omap_obj->vaddr = dma_alloc_writecombine(dev->dev, size, &omap_obj->paddr, GFP_KERNEL); - if (omap_obj->vaddr) - flags |= OMAP_BO_DMA; + if (!omap_obj->vaddr) { + kfree(omap_obj); + return NULL; + } + + flags |= OMAP_BO_DMA; } + spin_lock(&priv->list_lock); + list_add(&omap_obj->mm_list, &priv->obj_list); + spin_unlock(&priv->list_lock); + omap_obj->flags = flags; if (flags & OMAP_BO_TILED) { -- cgit v1.2.3-70-g09d2 From 7011bf4eccb63b4f34e4caa37a3a86f59d4031d4 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 19 Jun 2015 11:38:22 +0800 Subject: ACPICA: Linuxize: Replace __FUNCTION__ with __func__ ACPICA commit cb3d1c79f862cd368d749c9b8d9dced40111b0d0 __FUNCTION__ is MSVC only, in Linux, it is __func__. Lv Zheng. As noted by Christoph Hellwig: "__func__ is in C99 and never. __FUNCTION__ is an old extension supported by various compilers." In ACPICA, this is achieved by string replacement in release script and this patch contains the source code difference between the Linux upstream and ACPICA that is caused by the back porting. Link: https://github.com/acpica/acpica/commit/cb3d1c79 Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/utdebug.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c index 4f3f888d33bb..cd02693841db 100644 --- a/drivers/acpi/acpica/utdebug.c +++ b/drivers/acpi/acpica/utdebug.c @@ -111,8 +111,8 @@ void acpi_ut_track_stack_ptr(void) * RETURN: Updated pointer to the function name * * DESCRIPTION: Remove the "Acpi" prefix from the function name, if present. - * This allows compiler macros such as __func__ to be used with no - * change to the debug output. + * This allows compiler macros such as __func__ to be used + * with no change to the debug output. * ******************************************************************************/ -- cgit v1.2.3-70-g09d2 From eeeee40fcc3f92745639cfb166854656dddeb040 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 24 Jun 2015 14:25:54 -0700 Subject: Input: axp20x-pek - fix reporting button state as inverted Currently we are reporting the button state as inverted on all boards with an axp209 pmic, tested on a ba10-tvbox, bananapi, bananapro, cubietruck and utoo-p66 tablet. The axp209 datasheet clearly states that the power button must be connected between the PWRON key and ground. Which means that on a press we will get a falling edge (dbf) irq not a rising one, and likewise on release we will get a rising edge (dbr) irq, not a falling one. This commit swaps the check for the 2 irqs fixing the inverted reporting of the power button state. Signed-off-by: Hans de Goede Acked-by: Chen-Yu Tsai Acked-by: Carlo Caione Signed-off-by: Dmitry Torokhov --- drivers/input/misc/axp20x-pek.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/axp20x-pek.c b/drivers/input/misc/axp20x-pek.c index f1c844739cd7..10e140af5aac 100644 --- a/drivers/input/misc/axp20x-pek.c +++ b/drivers/input/misc/axp20x-pek.c @@ -167,9 +167,13 @@ static irqreturn_t axp20x_pek_irq(int irq, void *pwr) struct input_dev *idev = pwr; struct axp20x_pek *axp20x_pek = input_get_drvdata(idev); - if (irq == axp20x_pek->irq_dbr) + /* + * The power-button is connected to ground so a falling edge (dbf) + * means it is pressed. + */ + if (irq == axp20x_pek->irq_dbf) input_report_key(idev, KEY_POWER, true); - else if (irq == axp20x_pek->irq_dbf) + else if (irq == axp20x_pek->irq_dbr) input_report_key(idev, KEY_POWER, false); input_sync(idev); -- cgit v1.2.3-70-g09d2 From 3e30c11c8a902de350281a0d821e17cdb45ef156 Mon Sep 17 00:00:00 2001 From: HungNien Chen Date: Mon, 15 Jun 2015 18:57:08 +0300 Subject: Input: add a driver for wdt87xx touchscreen controller This is a driver for Weida HiTech WDT87xx series touchscreen controller. Signed-off-by: HungNien Chen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 12 + drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/wdt87xx_i2c.c | 1140 +++++++++++++++++++++++++++++++ 3 files changed, 1153 insertions(+) create mode 100644 drivers/input/touchscreen/wdt87xx_i2c.c (limited to 'drivers') diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index a398d636ca39..aa2b5f21b89b 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -658,6 +658,18 @@ config TOUCHSCREEN_PIXCIR To compile this driver as a module, choose M here: the module will be called pixcir_i2c_ts. +config TOUCHSCREEN_WDT87XX_I2C + tristate "Weida HiTech I2C touchscreen" + depends on I2C + help + Say Y here if you have a Weida WDT87XX I2C touchscreen + connected to your system. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called wdt87xx_i2c. + config TOUCHSCREEN_WM831X tristate "Support for WM831x touchscreen controllers" depends on MFD_WM831X diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 44deea743d02..fa3d33bac7fc 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -72,6 +72,7 @@ obj-$(CONFIG_TOUCHSCREEN_TSC2007) += tsc2007.o obj-$(CONFIG_TOUCHSCREEN_UCB1400) += ucb1400_ts.o obj-$(CONFIG_TOUCHSCREEN_WACOM_W8001) += wacom_w8001.o obj-$(CONFIG_TOUCHSCREEN_WACOM_I2C) += wacom_i2c.o +obj-$(CONFIG_TOUCHSCREEN_WDT87XX_I2C) += wdt87xx_i2c.o obj-$(CONFIG_TOUCHSCREEN_WM831X) += wm831x-ts.o obj-$(CONFIG_TOUCHSCREEN_WM97XX) += wm97xx-ts.o wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705) += wm9705.o diff --git a/drivers/input/touchscreen/wdt87xx_i2c.c b/drivers/input/touchscreen/wdt87xx_i2c.c new file mode 100644 index 000000000000..c073ea9345e2 --- /dev/null +++ b/drivers/input/touchscreen/wdt87xx_i2c.c @@ -0,0 +1,1140 @@ +/* + * Weida HiTech WDT87xx TouchScreen I2C driver + * + * Copyright (c) 2015 Weida Hi-Tech Co., Ltd. + * HN Chen + * + * This software is licensed under the terms of the GNU General Public + * License, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define WDT87XX_NAME "wdt87xx_i2c" +#define WDT87XX_DRV_VER "0.9.5" +#define WDT87XX_FW_NAME "wdt87xx_fw.bin" +#define WDT87XX_CFG_NAME "wdt87xx_cfg.bin" + +#define MODE_ACTIVE 0x01 +#define MODE_READY 0x02 +#define MODE_IDLE 0x03 +#define MODE_SLEEP 0x04 +#define MODE_STOP 0xFF + +#define WDT_MAX_FINGER 10 +#define WDT_RAW_BUF_COUNT 54 +#define WDT_V1_RAW_BUF_COUNT 74 +#define WDT_FIRMWARE_ID 0xa9e368f5 + +#define PG_SIZE 0x1000 +#define MAX_RETRIES 3 + +#define MAX_UNIT_AXIS 0x7FFF + +#define PKT_READ_SIZE 72 +#define PKT_WRITE_SIZE 80 + +/* the finger definition of the report event */ +#define FINGER_EV_OFFSET_ID 0 +#define FINGER_EV_OFFSET_X 1 +#define FINGER_EV_OFFSET_Y 3 +#define FINGER_EV_SIZE 5 + +#define FINGER_EV_V1_OFFSET_ID 0 +#define FINGER_EV_V1_OFFSET_W 1 +#define FINGER_EV_V1_OFFSET_P 2 +#define FINGER_EV_V1_OFFSET_X 3 +#define FINGER_EV_V1_OFFSET_Y 5 +#define FINGER_EV_V1_SIZE 7 + +/* The definition of a report packet */ +#define TOUCH_PK_OFFSET_REPORT_ID 0 +#define TOUCH_PK_OFFSET_EVENT 1 +#define TOUCH_PK_OFFSET_SCAN_TIME 51 +#define TOUCH_PK_OFFSET_FNGR_NUM 53 + +#define TOUCH_PK_V1_OFFSET_REPORT_ID 0 +#define TOUCH_PK_V1_OFFSET_EVENT 1 +#define TOUCH_PK_V1_OFFSET_SCAN_TIME 71 +#define TOUCH_PK_V1_OFFSET_FNGR_NUM 73 + +/* The definition of the controller parameters */ +#define CTL_PARAM_OFFSET_FW_ID 0 +#define CTL_PARAM_OFFSET_PLAT_ID 2 +#define CTL_PARAM_OFFSET_XMLS_ID1 4 +#define CTL_PARAM_OFFSET_XMLS_ID2 6 +#define CTL_PARAM_OFFSET_PHY_CH_X 8 +#define CTL_PARAM_OFFSET_PHY_CH_Y 10 +#define CTL_PARAM_OFFSET_PHY_X0 12 +#define CTL_PARAM_OFFSET_PHY_X1 14 +#define CTL_PARAM_OFFSET_PHY_Y0 16 +#define CTL_PARAM_OFFSET_PHY_Y1 18 +#define CTL_PARAM_OFFSET_PHY_W 22 +#define CTL_PARAM_OFFSET_PHY_H 24 + +/* Communication commands */ +#define PACKET_SIZE 56 +#define VND_REQ_READ 0x06 +#define VND_READ_DATA 0x07 +#define VND_REQ_WRITE 0x08 + +#define VND_CMD_START 0x00 +#define VND_CMD_STOP 0x01 +#define VND_CMD_RESET 0x09 + +#define VND_CMD_ERASE 0x1A + +#define VND_GET_CHECKSUM 0x66 + +#define VND_SET_DATA 0x83 +#define VND_SET_COMMAND_DATA 0x84 +#define VND_SET_CHECKSUM_CALC 0x86 +#define VND_SET_CHECKSUM_LENGTH 0x87 + +#define VND_CMD_SFLCK 0xFC +#define VND_CMD_SFUNL 0xFD + +#define CMD_SFLCK_KEY 0xC39B +#define CMD_SFUNL_KEY 0x95DA + +#define STRIDX_PLATFORM_ID 0x80 +#define STRIDX_PARAMETERS 0x81 + +#define CMD_BUF_SIZE 8 +#define PKT_BUF_SIZE 64 + +/* The definition of the command packet */ +#define CMD_REPORT_ID_OFFSET 0x0 +#define CMD_TYPE_OFFSET 0x1 +#define CMD_INDEX_OFFSET 0x2 +#define CMD_KEY_OFFSET 0x3 +#define CMD_LENGTH_OFFSET 0x4 +#define CMD_DATA_OFFSET 0x8 + +/* The definition of firmware chunk tags */ +#define FOURCC_ID_RIFF 0x46464952 +#define FOURCC_ID_WHIF 0x46494857 +#define FOURCC_ID_FRMT 0x544D5246 +#define FOURCC_ID_FRWR 0x52575246 +#define FOURCC_ID_CNFG 0x47464E43 + +#define CHUNK_ID_FRMT FOURCC_ID_FRMT +#define CHUNK_ID_FRWR FOURCC_ID_FRWR +#define CHUNK_ID_CNFG FOURCC_ID_CNFG + +#define FW_FOURCC1_OFFSET 0 +#define FW_SIZE_OFFSET 4 +#define FW_FOURCC2_OFFSET 8 +#define FW_PAYLOAD_OFFSET 40 + +#define FW_CHUNK_ID_OFFSET 0 +#define FW_CHUNK_SIZE_OFFSET 4 +#define FW_CHUNK_TGT_START_OFFSET 8 +#define FW_CHUNK_PAYLOAD_LEN_OFFSET 12 +#define FW_CHUNK_SRC_START_OFFSET 16 +#define FW_CHUNK_VERSION_OFFSET 20 +#define FW_CHUNK_ATTR_OFFSET 24 +#define FW_CHUNK_PAYLOAD_OFFSET 32 + +/* Controller requires minimum 300us between commands */ +#define WDT_COMMAND_DELAY_MS 2 +#define WDT_FLASH_WRITE_DELAY_MS 4 + +struct wdt87xx_sys_param { + u16 fw_id; + u16 plat_id; + u16 xmls_id1; + u16 xmls_id2; + u16 phy_ch_x; + u16 phy_ch_y; + u16 phy_w; + u16 phy_h; + u32 max_x; + u32 max_y; +}; + +struct wdt87xx_data { + struct i2c_client *client; + struct input_dev *input; + /* Mutex for fw update to prevent concurrent access */ + struct mutex fw_mutex; + struct wdt87xx_sys_param param; + u8 phys[32]; +}; + +static int wdt87xx_i2c_xfer(struct i2c_client *client, + void *txdata, size_t txlen, + void *rxdata, size_t rxlen) +{ + struct i2c_msg msgs[] = { + { + .addr = client->addr, + .flags = 0, + .len = txlen, + .buf = txdata, + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = rxlen, + .buf = rxdata, + }, + }; + int error; + int ret; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret != ARRAY_SIZE(msgs)) { + error = ret < 0 ? ret : -EIO; + dev_err(&client->dev, "%s: i2c transfer failed: %d\n", + __func__, error); + return error; + } + + return 0; +} + +static int wdt87xx_get_string(struct i2c_client *client, u8 str_idx, + u8 *buf, size_t len) +{ + u8 tx_buf[] = { 0x22, 0x00, 0x13, 0x0E, str_idx, 0x23, 0x00 }; + u8 rx_buf[PKT_WRITE_SIZE]; + size_t rx_len = len + 2; + int error; + + if (rx_len > sizeof(rx_buf)) + return -EINVAL; + + error = wdt87xx_i2c_xfer(client, tx_buf, sizeof(tx_buf), + rx_buf, rx_len); + if (error) { + dev_err(&client->dev, "get string failed: %d\n", error); + return error; + } + + if (rx_buf[1] != 0x03) { + dev_err(&client->dev, "unexpected response to get string: %d\n", + rx_buf[1]); + return -EINVAL; + } + + rx_len = min_t(size_t, len, rx_buf[0]); + memcpy(buf, &rx_buf[2], rx_len); + + mdelay(WDT_COMMAND_DELAY_MS); + + return 0; +} + +static int wdt87xx_get_feature(struct i2c_client *client, + u8 *buf, size_t buf_size) +{ + u8 tx_buf[8]; + u8 rx_buf[PKT_WRITE_SIZE]; + size_t tx_len = 0; + size_t rx_len = buf_size + 2; + int error; + + if (rx_len > sizeof(rx_buf)) + return -EINVAL; + + /* Get feature command packet */ + tx_buf[tx_len++] = 0x22; + tx_buf[tx_len++] = 0x00; + if (buf[CMD_REPORT_ID_OFFSET] > 0xF) { + tx_buf[tx_len++] = 0x30; + tx_buf[tx_len++] = 0x02; + tx_buf[tx_len++] = buf[CMD_REPORT_ID_OFFSET]; + } else { + tx_buf[tx_len++] = 0x30 | buf[CMD_REPORT_ID_OFFSET]; + tx_buf[tx_len++] = 0x02; + } + tx_buf[tx_len++] = 0x23; + tx_buf[tx_len++] = 0x00; + + error = wdt87xx_i2c_xfer(client, tx_buf, tx_len, rx_buf, rx_len); + if (error) { + dev_err(&client->dev, "get feature failed: %d\n", error); + return error; + } + + rx_len = min_t(size_t, buf_size, get_unaligned_le16(rx_buf)); + memcpy(buf, &rx_buf[2], rx_len); + + mdelay(WDT_COMMAND_DELAY_MS); + + return 0; +} + +static int wdt87xx_set_feature(struct i2c_client *client, + const u8 *buf, size_t buf_size) +{ + u8 tx_buf[PKT_WRITE_SIZE]; + int tx_len = 0; + int error; + + /* Set feature command packet */ + tx_buf[tx_len++] = 0x22; + tx_buf[tx_len++] = 0x00; + if (buf[CMD_REPORT_ID_OFFSET] > 0xF) { + tx_buf[tx_len++] = 0x30; + tx_buf[tx_len++] = 0x03; + tx_buf[tx_len++] = buf[CMD_REPORT_ID_OFFSET]; + } else { + tx_buf[tx_len++] = 0x30 | buf[CMD_REPORT_ID_OFFSET]; + tx_buf[tx_len++] = 0x03; + } + tx_buf[tx_len++] = 0x23; + tx_buf[tx_len++] = 0x00; + tx_buf[tx_len++] = (buf_size & 0xFF); + tx_buf[tx_len++] = ((buf_size & 0xFF00) >> 8); + + if (tx_len + buf_size > sizeof(tx_buf)) + return -EINVAL; + + memcpy(&tx_buf[tx_len], buf, buf_size); + tx_len += buf_size; + + error = i2c_master_send(client, tx_buf, tx_len); + if (error < 0) { + dev_err(&client->dev, "set feature failed: %d\n", error); + return error; + } + + mdelay(WDT_COMMAND_DELAY_MS); + + return 0; +} + +static int wdt87xx_send_command(struct i2c_client *client, int cmd, int value) +{ + u8 cmd_buf[CMD_BUF_SIZE]; + + /* Set the command packet */ + cmd_buf[CMD_REPORT_ID_OFFSET] = VND_REQ_WRITE; + cmd_buf[CMD_TYPE_OFFSET] = VND_SET_COMMAND_DATA; + put_unaligned_le16((u16)cmd, &cmd_buf[CMD_INDEX_OFFSET]); + + switch (cmd) { + case VND_CMD_START: + case VND_CMD_STOP: + case VND_CMD_RESET: + /* Mode selector */ + put_unaligned_le32((value & 0xFF), &cmd_buf[CMD_LENGTH_OFFSET]); + break; + + case VND_CMD_SFLCK: + put_unaligned_le16(CMD_SFLCK_KEY, &cmd_buf[CMD_KEY_OFFSET]); + break; + + case VND_CMD_SFUNL: + put_unaligned_le16(CMD_SFUNL_KEY, &cmd_buf[CMD_KEY_OFFSET]); + break; + + case VND_CMD_ERASE: + case VND_SET_CHECKSUM_CALC: + case VND_SET_CHECKSUM_LENGTH: + put_unaligned_le32(value, &cmd_buf[CMD_KEY_OFFSET]); + break; + + default: + cmd_buf[CMD_REPORT_ID_OFFSET] = 0; + dev_err(&client->dev, "Invalid command: %d\n", cmd); + return -EINVAL; + } + + return wdt87xx_set_feature(client, cmd_buf, sizeof(cmd_buf)); +} + +static int wdt87xx_sw_reset(struct i2c_client *client) +{ + int error; + + dev_dbg(&client->dev, "resetting device now\n"); + + error = wdt87xx_send_command(client, VND_CMD_RESET, 0); + if (error) { + dev_err(&client->dev, "reset failed\n"); + return error; + } + + /* Wait the device to be ready */ + msleep(200); + + return 0; +} + +static const void *wdt87xx_get_fw_chunk(const struct firmware *fw, u32 id) +{ + size_t pos = FW_PAYLOAD_OFFSET; + u32 chunk_id, chunk_size; + + while (pos < fw->size) { + chunk_id = get_unaligned_le32(fw->data + + pos + FW_CHUNK_ID_OFFSET); + if (chunk_id == id) + return fw->data + pos; + + chunk_size = get_unaligned_le32(fw->data + + pos + FW_CHUNK_SIZE_OFFSET); + pos += chunk_size + 2 * sizeof(u32); /* chunk ID + size */ + } + + return NULL; +} + +static int wdt87xx_get_sysparam(struct i2c_client *client, + struct wdt87xx_sys_param *param) +{ + u8 buf[PKT_READ_SIZE]; + int error; + + error = wdt87xx_get_string(client, STRIDX_PARAMETERS, buf, 32); + if (error) { + dev_err(&client->dev, "failed to get parameters\n"); + return error; + } + + param->xmls_id1 = get_unaligned_le16(buf + CTL_PARAM_OFFSET_XMLS_ID1); + param->xmls_id2 = get_unaligned_le16(buf + CTL_PARAM_OFFSET_XMLS_ID2); + param->phy_ch_x = get_unaligned_le16(buf + CTL_PARAM_OFFSET_PHY_CH_X); + param->phy_ch_y = get_unaligned_le16(buf + CTL_PARAM_OFFSET_PHY_CH_Y); + param->phy_w = get_unaligned_le16(buf + CTL_PARAM_OFFSET_PHY_W) / 10; + param->phy_h = get_unaligned_le16(buf + CTL_PARAM_OFFSET_PHY_H) / 10; + + param->max_x = MAX_UNIT_AXIS; + param->max_y = DIV_ROUND_CLOSEST(MAX_UNIT_AXIS * param->phy_h, + param->phy_w); + + error = wdt87xx_get_string(client, STRIDX_PLATFORM_ID, buf, 8); + if (error) { + dev_err(&client->dev, "failed to get platform id\n"); + return error; + } + + param->plat_id = buf[1]; + + buf[0] = 0xf2; + error = wdt87xx_get_feature(client, buf, 16); + if (error) { + dev_err(&client->dev, "failed to get firmware id\n"); + return error; + } + + if (buf[0] != 0xf2) { + dev_err(&client->dev, "wrong id of fw response: 0x%x\n", + buf[0]); + return -EINVAL; + } + + param->fw_id = get_unaligned_le16(&buf[1]); + + dev_info(&client->dev, + "fw_id: 0x%x, plat_id: 0x%x\nxml_id1: %04x, xml_id2: %04x\n", + param->fw_id, param->plat_id, + param->xmls_id1, param->xmls_id2); + + return 0; +} + +static int wdt87xx_validate_firmware(struct wdt87xx_data *wdt, + const struct firmware *fw) +{ + const void *fw_chunk; + u32 data1, data2; + u32 size; + u8 fw_chip_id; + u8 chip_id; + + data1 = get_unaligned_le32(fw->data + FW_FOURCC1_OFFSET); + data2 = get_unaligned_le32(fw->data + FW_FOURCC2_OFFSET); + if (data1 != FOURCC_ID_RIFF || data2 != FOURCC_ID_WHIF) { + dev_err(&wdt->client->dev, "check fw tag failed\n"); + return -EINVAL; + } + + size = get_unaligned_le32(fw->data + FW_SIZE_OFFSET); + if (size != fw->size) { + dev_err(&wdt->client->dev, + "fw size mismatch: expected %d, actual %zd\n", + size, fw->size); + return -EINVAL; + } + + /* + * Get the chip_id from the firmware. Make sure that it is the + * right controller to do the firmware and config update. + */ + fw_chunk = wdt87xx_get_fw_chunk(fw, CHUNK_ID_FRWR); + if (!fw_chunk) { + dev_err(&wdt->client->dev, + "unable to locate firmware chunk\n"); + return -EINVAL; + } + + fw_chip_id = (get_unaligned_le32(fw_chunk + + FW_CHUNK_VERSION_OFFSET) >> 12) & 0xF; + chip_id = (wdt->param.fw_id >> 12) & 0xF; + + if (fw_chip_id != chip_id) { + dev_err(&wdt->client->dev, + "fw version mismatch: fw %d vs. chip %d\n", + fw_chip_id, chip_id); + return -ENODEV; + } + + return 0; +} + +static int wdt87xx_validate_fw_chunk(const void *data, int id) +{ + if (id == CHUNK_ID_FRWR) { + u32 fw_id; + + fw_id = get_unaligned_le32(data + FW_CHUNK_PAYLOAD_OFFSET); + if (fw_id != WDT_FIRMWARE_ID) + return -EINVAL; + } + + return 0; +} + +static int wdt87xx_write_data(struct i2c_client *client, const char *data, + u32 address, int length) +{ + u16 packet_size; + int count = 0; + int error; + u8 pkt_buf[PKT_BUF_SIZE]; + + /* Address and length should be 4 bytes aligned */ + if ((address & 0x3) != 0 || (length & 0x3) != 0) { + dev_err(&client->dev, + "addr & len must be 4 bytes aligned %x, %x\n", + address, length); + return -EINVAL; + } + + while (length) { + packet_size = min(length, PACKET_SIZE); + + pkt_buf[CMD_REPORT_ID_OFFSET] = VND_REQ_WRITE; + pkt_buf[CMD_TYPE_OFFSET] = VND_SET_DATA; + put_unaligned_le16(packet_size, &pkt_buf[CMD_INDEX_OFFSET]); + put_unaligned_le32(address, &pkt_buf[CMD_LENGTH_OFFSET]); + memcpy(&pkt_buf[CMD_DATA_OFFSET], data, packet_size); + + error = wdt87xx_set_feature(client, pkt_buf, sizeof(pkt_buf)); + if (error) + return error; + + length -= packet_size; + data += packet_size; + address += packet_size; + + /* Wait for the controller to finish the write */ + mdelay(WDT_FLASH_WRITE_DELAY_MS); + + if ((++count % 32) == 0) { + /* Delay for fw to clear watch dog */ + msleep(20); + } + } + + return 0; +} + +static u16 misr(u16 cur_value, u8 new_value) +{ + u32 a, b; + u32 bit0; + u32 y; + + a = cur_value; + b = new_value; + bit0 = a ^ (b & 1); + bit0 ^= a >> 1; + bit0 ^= a >> 2; + bit0 ^= a >> 4; + bit0 ^= a >> 5; + bit0 ^= a >> 7; + bit0 ^= a >> 11; + bit0 ^= a >> 15; + y = (a << 1) ^ b; + y = (y & ~1) | (bit0 & 1); + + return (u16)y; +} + +static u16 wdt87xx_calculate_checksum(const u8 *data, size_t length) +{ + u16 checksum = 0; + size_t i; + + for (i = 0; i < length; i++) + checksum = misr(checksum, data[i]); + + return checksum; +} + +static int wdt87xx_get_checksum(struct i2c_client *client, u16 *checksum, + u32 address, int length) +{ + int error; + int time_delay; + u8 pkt_buf[PKT_BUF_SIZE]; + u8 cmd_buf[CMD_BUF_SIZE]; + + error = wdt87xx_send_command(client, VND_SET_CHECKSUM_LENGTH, length); + if (error) { + dev_err(&client->dev, "failed to set checksum length\n"); + return error; + } + + error = wdt87xx_send_command(client, VND_SET_CHECKSUM_CALC, address); + if (error) { + dev_err(&client->dev, "failed to set checksum address\n"); + return error; + } + + /* Wait the operation to complete */ + time_delay = DIV_ROUND_UP(length, 1024); + msleep(time_delay * 30); + + memset(cmd_buf, 0, sizeof(cmd_buf)); + cmd_buf[CMD_REPORT_ID_OFFSET] = VND_REQ_READ; + cmd_buf[CMD_TYPE_OFFSET] = VND_GET_CHECKSUM; + error = wdt87xx_set_feature(client, cmd_buf, sizeof(cmd_buf)); + if (error) { + dev_err(&client->dev, "failed to request checksum\n"); + return error; + } + + memset(pkt_buf, 0, sizeof(pkt_buf)); + pkt_buf[CMD_REPORT_ID_OFFSET] = VND_READ_DATA; + error = wdt87xx_get_feature(client, pkt_buf, sizeof(pkt_buf)); + if (error) { + dev_err(&client->dev, "failed to read checksum\n"); + return error; + } + + *checksum = get_unaligned_le16(&pkt_buf[CMD_DATA_OFFSET]); + return 0; +} + +static int wdt87xx_write_firmware(struct i2c_client *client, const void *chunk) +{ + u32 start_addr = get_unaligned_le32(chunk + FW_CHUNK_TGT_START_OFFSET); + u32 size = get_unaligned_le32(chunk + FW_CHUNK_PAYLOAD_LEN_OFFSET); + const void *data = chunk + FW_CHUNK_PAYLOAD_OFFSET; + int error; + int err1; + int page_size; + int retry = 0; + u16 device_checksum, firmware_checksum; + + dev_dbg(&client->dev, "start 4k page program\n"); + + error = wdt87xx_send_command(client, VND_CMD_STOP, MODE_STOP); + if (error) { + dev_err(&client->dev, "stop report mode failed\n"); + return error; + } + + error = wdt87xx_send_command(client, VND_CMD_SFUNL, 0); + if (error) { + dev_err(&client->dev, "unlock failed\n"); + goto out_enable_reporting; + } + + mdelay(10); + + while (size) { + dev_dbg(&client->dev, "%s: %x, %x\n", __func__, + start_addr, size); + + page_size = min_t(u32, size, PG_SIZE); + size -= page_size; + + for (retry = 0; retry < MAX_RETRIES; retry++) { + error = wdt87xx_send_command(client, VND_CMD_ERASE, + start_addr); + if (error) { + dev_err(&client->dev, + "erase failed at %#08x\n", start_addr); + break; + } + + msleep(50); + + error = wdt87xx_write_data(client, data, start_addr, + page_size); + if (error) { + dev_err(&client->dev, + "write failed at %#08x (%d bytes)\n", + start_addr, page_size); + break; + } + + error = wdt87xx_get_checksum(client, &device_checksum, + start_addr, page_size); + if (error) { + dev_err(&client->dev, + "failed to retrieve checksum for %#08x (len: %d)\n", + start_addr, page_size); + break; + } + + firmware_checksum = + wdt87xx_calculate_checksum(data, page_size); + + if (device_checksum == firmware_checksum) + break; + + dev_err(&client->dev, + "checksum fail: %d vs %d, retry %d\n", + device_checksum, firmware_checksum, retry); + } + + if (retry == MAX_RETRIES) { + dev_err(&client->dev, "page write failed\n"); + error = -EIO; + goto out_lock_device; + } + + start_addr = start_addr + page_size; + data = data + page_size; + } + +out_lock_device: + err1 = wdt87xx_send_command(client, VND_CMD_SFLCK, 0); + if (err1) + dev_err(&client->dev, "lock failed\n"); + + mdelay(10); + +out_enable_reporting: + err1 = wdt87xx_send_command(client, VND_CMD_START, 0); + if (err1) + dev_err(&client->dev, "start to report failed\n"); + + return error ? error : err1; +} + +static int wdt87xx_load_chunk(struct i2c_client *client, + const struct firmware *fw, u32 ck_id) +{ + const void *chunk; + int error; + + chunk = wdt87xx_get_fw_chunk(fw, ck_id); + if (!chunk) { + dev_err(&client->dev, "unable to locate chunk (type %d)\n", + ck_id); + return -EINVAL; + } + + error = wdt87xx_validate_fw_chunk(chunk, ck_id); + if (error) { + dev_err(&client->dev, "invalid chunk (type %d): %d\n", + ck_id, error); + return error; + } + + error = wdt87xx_write_firmware(client, chunk); + if (error) { + dev_err(&client->dev, + "failed to write fw chunk (type %d): %d\n", + ck_id, error); + return error; + } + + return 0; +} + +static int wdt87xx_do_update_firmware(struct i2c_client *client, + const struct firmware *fw, + unsigned int chunk_id) +{ + struct wdt87xx_data *wdt = i2c_get_clientdata(client); + int error; + + error = wdt87xx_validate_firmware(wdt, fw); + if (error) + return error; + + error = mutex_lock_interruptible(&wdt->fw_mutex); + if (error) + return error; + + disable_irq(client->irq); + + error = wdt87xx_load_chunk(client, fw, chunk_id); + if (error) { + dev_err(&client->dev, + "firmware load failed (type: %d): %d\n", + chunk_id, error); + goto out; + } + + error = wdt87xx_sw_reset(client); + if (error) { + dev_err(&client->dev, "soft reset failed: %d\n", error); + goto out; + } + + /* Refresh the parameters */ + error = wdt87xx_get_sysparam(client, &wdt->param); + if (error) + dev_err(&client->dev, + "failed to refresh system paramaters: %d\n", error); +out: + enable_irq(client->irq); + mutex_unlock(&wdt->fw_mutex); + + return error ? error : 0; +} + +static int wdt87xx_update_firmware(struct device *dev, + const char *fw_name, unsigned int chunk_id) +{ + struct i2c_client *client = to_i2c_client(dev); + const struct firmware *fw; + int error; + + error = request_firmware(&fw, fw_name, dev); + if (error) { + dev_err(&client->dev, "unable to retrieve firmware %s: %d\n", + fw_name, error); + return error; + } + + error = wdt87xx_do_update_firmware(client, fw, chunk_id); + + release_firmware(fw); + + return error ? error : 0; +} + +static ssize_t config_csum_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct wdt87xx_data *wdt = i2c_get_clientdata(client); + u32 cfg_csum; + + cfg_csum = wdt->param.xmls_id1; + cfg_csum = (cfg_csum << 16) | wdt->param.xmls_id2; + + return scnprintf(buf, PAGE_SIZE, "%x\n", cfg_csum); +} + +static ssize_t fw_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct wdt87xx_data *wdt = i2c_get_clientdata(client); + + return scnprintf(buf, PAGE_SIZE, "%x\n", wdt->param.fw_id); +} + +static ssize_t plat_id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct wdt87xx_data *wdt = i2c_get_clientdata(client); + + return scnprintf(buf, PAGE_SIZE, "%x\n", wdt->param.plat_id); +} + +static ssize_t update_config_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int error; + + error = wdt87xx_update_firmware(dev, WDT87XX_CFG_NAME, CHUNK_ID_CNFG); + + return error ? error : count; +} + +static ssize_t update_fw_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int error; + + error = wdt87xx_update_firmware(dev, WDT87XX_FW_NAME, CHUNK_ID_FRWR); + + return error ? error : count; +} + +static DEVICE_ATTR_RO(config_csum); +static DEVICE_ATTR_RO(fw_version); +static DEVICE_ATTR_RO(plat_id); +static DEVICE_ATTR_WO(update_config); +static DEVICE_ATTR_WO(update_fw); + +static struct attribute *wdt87xx_attrs[] = { + &dev_attr_config_csum.attr, + &dev_attr_fw_version.attr, + &dev_attr_plat_id.attr, + &dev_attr_update_config.attr, + &dev_attr_update_fw.attr, + NULL +}; + +static const struct attribute_group wdt87xx_attr_group = { + .attrs = wdt87xx_attrs, +}; + +static void wdt87xx_report_contact(struct input_dev *input, + struct wdt87xx_sys_param *param, + u8 *buf) +{ + int finger_id; + u32 x, y; + u8 w, p; + + finger_id = (buf[FINGER_EV_V1_OFFSET_ID] >> 3) - 1; + if (finger_id < 0) + return; + + /* Check if this is an active contact */ + if (!(buf[FINGER_EV_V1_OFFSET_ID] & 0x1)) + return; + + w = buf[FINGER_EV_V1_OFFSET_W]; + p = buf[FINGER_EV_V1_OFFSET_P]; + + x = get_unaligned_le16(buf + FINGER_EV_V1_OFFSET_X); + + y = get_unaligned_le16(buf + FINGER_EV_V1_OFFSET_Y); + y = DIV_ROUND_CLOSEST(y * param->phy_h, param->phy_w); + + /* Refuse incorrect coordinates */ + if (x > param->max_x || y > param->max_y) + return; + + dev_dbg(input->dev.parent, "tip on (%d), x(%d), y(%d)\n", + finger_id, x, y); + + input_mt_slot(input, finger_id); + input_mt_report_slot_state(input, MT_TOOL_FINGER, 1); + input_report_abs(input, ABS_MT_TOUCH_MAJOR, w); + input_report_abs(input, ABS_MT_PRESSURE, p); + input_report_abs(input, ABS_MT_POSITION_X, x); + input_report_abs(input, ABS_MT_POSITION_Y, y); +} + +static irqreturn_t wdt87xx_ts_interrupt(int irq, void *dev_id) +{ + struct wdt87xx_data *wdt = dev_id; + struct i2c_client *client = wdt->client; + int i, fingers; + int error; + u8 raw_buf[WDT_V1_RAW_BUF_COUNT] = {0}; + + error = i2c_master_recv(client, raw_buf, WDT_V1_RAW_BUF_COUNT); + if (error < 0) { + dev_err(&client->dev, "read v1 raw data failed: %d\n", error); + goto irq_exit; + } + + fingers = raw_buf[TOUCH_PK_V1_OFFSET_FNGR_NUM]; + if (!fingers) + goto irq_exit; + + for (i = 0; i < WDT_MAX_FINGER; i++) + wdt87xx_report_contact(wdt->input, + &wdt->param, + &raw_buf[TOUCH_PK_V1_OFFSET_EVENT + + i * FINGER_EV_V1_SIZE]); + + input_mt_sync_frame(wdt->input); + input_sync(wdt->input); + +irq_exit: + return IRQ_HANDLED; +} + +static int wdt87xx_ts_create_input_device(struct wdt87xx_data *wdt) +{ + struct device *dev = &wdt->client->dev; + struct input_dev *input; + unsigned int res = DIV_ROUND_CLOSEST(MAX_UNIT_AXIS, wdt->param.phy_w); + int error; + + input = devm_input_allocate_device(dev); + if (!input) { + dev_err(dev, "failed to allocate input device\n"); + return -ENOMEM; + } + wdt->input = input; + + input->name = "WDT87xx Touchscreen"; + input->id.bustype = BUS_I2C; + input->phys = wdt->phys; + + input_set_abs_params(input, ABS_MT_POSITION_X, 0, + wdt->param.max_x, 0, 0); + input_set_abs_params(input, ABS_MT_POSITION_Y, 0, + wdt->param.max_y, 0, 0); + input_abs_set_res(input, ABS_MT_POSITION_X, res); + input_abs_set_res(input, ABS_MT_POSITION_Y, res); + + input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 0xFF, 0, 0); + input_set_abs_params(input, ABS_MT_PRESSURE, 0, 0xFF, 0, 0); + + input_mt_init_slots(input, WDT_MAX_FINGER, + INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); + + error = input_register_device(input); + if (error) { + dev_err(dev, "failed to register input device: %d\n", error); + return error; + } + + return 0; +} + +static int wdt87xx_ts_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct wdt87xx_data *wdt; + int error; + + dev_dbg(&client->dev, "adapter=%d, client irq: %d\n", + client->adapter->nr, client->irq); + + /* Check if the I2C function is ok in this adaptor */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return -ENXIO; + + wdt = devm_kzalloc(&client->dev, sizeof(*wdt), GFP_KERNEL); + if (!wdt) + return -ENOMEM; + + wdt->client = client; + mutex_init(&wdt->fw_mutex); + i2c_set_clientdata(client, wdt); + + snprintf(wdt->phys, sizeof(wdt->phys), "i2c-%u-%04x/input0", + client->adapter->nr, client->addr); + + error = wdt87xx_get_sysparam(client, &wdt->param); + if (error) + return error; + + error = wdt87xx_ts_create_input_device(wdt); + if (error) + return error; + + error = devm_request_threaded_irq(&client->dev, client->irq, + NULL, wdt87xx_ts_interrupt, + IRQF_ONESHOT, + client->name, wdt); + if (error) { + dev_err(&client->dev, "request irq failed: %d\n", error); + return error; + } + + error = sysfs_create_group(&client->dev.kobj, &wdt87xx_attr_group); + if (error) { + dev_err(&client->dev, "create sysfs failed: %d\n", error); + return error; + } + + return 0; +} + +static int wdt87xx_ts_remove(struct i2c_client *client) +{ + sysfs_remove_group(&client->dev.kobj, &wdt87xx_attr_group); + + return 0; +} + +static int __maybe_unused wdt87xx_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + int error; + + disable_irq(client->irq); + + error = wdt87xx_send_command(client, VND_CMD_STOP, MODE_IDLE); + if (error) { + enable_irq(client->irq); + dev_err(&client->dev, + "failed to stop device when suspending: %d\n", + error); + return error; + } + + return 0; +} + +static int __maybe_unused wdt87xx_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + int error; + + /* + * The chip may have been reset while system is resuming, + * give it some time to settle. + */ + mdelay(100); + + error = wdt87xx_send_command(client, VND_CMD_START, 0); + if (error) + dev_err(&client->dev, + "failed to start device when resuming: %d\n", + error); + + enable_irq(client->irq); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(wdt87xx_pm_ops, wdt87xx_suspend, wdt87xx_resume); + +static const struct i2c_device_id wdt87xx_dev_id[] = { + { WDT87XX_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, wdt87xx_dev_id); + +static const struct acpi_device_id wdt87xx_acpi_id[] = { + { "WDHT0001", 0 }, + { } +}; +MODULE_DEVICE_TABLE(acpi, wdt87xx_acpi_id); + +static struct i2c_driver wdt87xx_driver = { + .probe = wdt87xx_ts_probe, + .remove = wdt87xx_ts_remove, + .id_table = wdt87xx_dev_id, + .driver = { + .name = WDT87XX_NAME, + .pm = &wdt87xx_pm_ops, + .acpi_match_table = ACPI_PTR(wdt87xx_acpi_id), + }, +}; +module_i2c_driver(wdt87xx_driver); + +MODULE_AUTHOR("HN Chen "); +MODULE_DESCRIPTION("WeidaHiTech WDT87XX Touchscreen driver"); +MODULE_VERSION(WDT87XX_DRV_VER); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-70-g09d2 From b8830a4e71b15d0364ac8e6c55301eea73f211da Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Tue, 23 Jun 2015 10:11:19 +0200 Subject: dell-laptop: Fix allocating & freeing SMI buffer page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit fix kernel crash when probing for rfkill devices in dell-laptop driver failed. Function free_page() was incorrectly used on struct page * instead of virtual address of SMI buffer. This commit also simplify allocating page for SMI buffer by using __get_free_page() function instead of sequential call of functions alloc_page() and page_address(). Signed-off-by: Pali Rohár Acked-by: Michal Hocko Cc: stable@vger.kernel.org Signed-off-by: Darren Hart --- drivers/platform/x86/dell-laptop.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index 9724613c28a6..35758cbc6bc8 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -306,7 +306,6 @@ static const struct dmi_system_id dell_quirks[] __initconst = { }; static struct calling_interface_buffer *buffer; -static struct page *bufferpage; static DEFINE_MUTEX(buffer_mutex); static int hwswitch_state; @@ -2068,12 +2067,11 @@ static int __init dell_init(void) * Allocate buffer below 4GB for SMI data--only 32-bit physical addr * is passed to SMI handler. */ - bufferpage = alloc_page(GFP_KERNEL | GFP_DMA32); - if (!bufferpage) { + buffer = (void *)__get_free_page(GFP_KERNEL | GFP_DMA32); + if (!buffer) { ret = -ENOMEM; goto fail_buffer; } - buffer = page_address(bufferpage); ret = dell_setup_rfkill(); @@ -2135,7 +2133,7 @@ static int __init dell_init(void) fail_backlight: dell_cleanup_rfkill(); fail_rfkill: - free_page((unsigned long)bufferpage); + free_page((unsigned long)buffer); fail_buffer: platform_device_del(platform_device); fail_platform_device2: -- cgit v1.2.3-70-g09d2 From 144cba1493fdd6e3e1980e439a31df877831ebcd Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Mon, 27 Apr 2015 11:09:54 +0800 Subject: libceph: allow setting osd_req_op's flags Signed-off-by: Yan, Zheng Reviewed-by: Alex Elder --- drivers/block/rbd.c | 4 ++-- fs/ceph/addr.c | 3 ++- fs/ceph/file.c | 2 +- include/linux/ceph/osd_client.h | 2 +- net/ceph/osd_client.c | 24 +++++++++++++++--------- 5 files changed, 21 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index ec6c5c6e1ac9..349115ae3bc2 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -2376,7 +2376,7 @@ static void rbd_img_obj_request_fill(struct rbd_obj_request *obj_request, } if (opcode == CEPH_OSD_OP_DELETE) - osd_req_op_init(osd_request, num_ops, opcode); + osd_req_op_init(osd_request, num_ops, opcode, 0); else osd_req_op_extent_init(osd_request, num_ops, opcode, offset, length, 0, 0); @@ -2848,7 +2848,7 @@ static int rbd_img_obj_exists_submit(struct rbd_obj_request *obj_request) goto out; stat_request->callback = rbd_img_obj_exists_callback; - osd_req_op_init(stat_request->osd_req, 0, CEPH_OSD_OP_STAT); + osd_req_op_init(stat_request->osd_req, 0, CEPH_OSD_OP_STAT, 0); osd_req_op_raw_data_in_pages(stat_request->osd_req, 0, pages, size, 0, false, false); rbd_osd_req_format_read(stat_request); diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index e162bcd105ee..feeaf3b65fa0 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -884,7 +884,8 @@ get_more_pages: } if (do_sync) - osd_req_op_init(req, 1, CEPH_OSD_OP_STARTSYNC); + osd_req_op_init(req, 1, + CEPH_OSD_OP_STARTSYNC, 0); req->r_callback = writepages_finish; req->r_inode = inode; diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 3b6b522b4b31..777eb21d556f 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -614,7 +614,7 @@ ceph_sync_direct_write(struct kiocb *iocb, struct iov_iter *from, loff_t pos) break; } - osd_req_op_init(req, 1, CEPH_OSD_OP_STARTSYNC); + osd_req_op_init(req, 1, CEPH_OSD_OP_STARTSYNC, 0); n = iov_iter_get_pages_alloc(from, &pages, len, &start); if (unlikely(n < 0)) { diff --git a/include/linux/ceph/osd_client.h b/include/linux/ceph/osd_client.h index 61b19c46bdb3..7506b485bb6d 100644 --- a/include/linux/ceph/osd_client.h +++ b/include/linux/ceph/osd_client.h @@ -249,7 +249,7 @@ extern void ceph_osdc_handle_map(struct ceph_osd_client *osdc, struct ceph_msg *msg); extern void osd_req_op_init(struct ceph_osd_request *osd_req, - unsigned int which, u16 opcode); + unsigned int which, u16 opcode, u32 flags); extern void osd_req_op_raw_data_in_pages(struct ceph_osd_request *, unsigned int which, diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 72459b9df8a1..4cb4fab46e4f 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -453,7 +453,7 @@ __CEPH_FORALL_OSD_OPS(GENERATE_CASE) */ static struct ceph_osd_req_op * _osd_req_op_init(struct ceph_osd_request *osd_req, unsigned int which, - u16 opcode) + u16 opcode, u32 flags) { struct ceph_osd_req_op *op; @@ -463,14 +463,15 @@ _osd_req_op_init(struct ceph_osd_request *osd_req, unsigned int which, op = &osd_req->r_ops[which]; memset(op, 0, sizeof (*op)); op->op = opcode; + op->flags = flags; return op; } void osd_req_op_init(struct ceph_osd_request *osd_req, - unsigned int which, u16 opcode) + unsigned int which, u16 opcode, u32 flags) { - (void)_osd_req_op_init(osd_req, which, opcode); + (void)_osd_req_op_init(osd_req, which, opcode, flags); } EXPORT_SYMBOL(osd_req_op_init); @@ -479,7 +480,8 @@ void osd_req_op_extent_init(struct ceph_osd_request *osd_req, u64 offset, u64 length, u64 truncate_size, u32 truncate_seq) { - struct ceph_osd_req_op *op = _osd_req_op_init(osd_req, which, opcode); + struct ceph_osd_req_op *op = _osd_req_op_init(osd_req, which, + opcode, 0); size_t payload_len = 0; BUG_ON(opcode != CEPH_OSD_OP_READ && opcode != CEPH_OSD_OP_WRITE && @@ -518,7 +520,8 @@ EXPORT_SYMBOL(osd_req_op_extent_update); void osd_req_op_cls_init(struct ceph_osd_request *osd_req, unsigned int which, u16 opcode, const char *class, const char *method) { - struct ceph_osd_req_op *op = _osd_req_op_init(osd_req, which, opcode); + struct ceph_osd_req_op *op = _osd_req_op_init(osd_req, which, + opcode, 0); struct ceph_pagelist *pagelist; size_t payload_len = 0; size_t size; @@ -555,7 +558,8 @@ int osd_req_op_xattr_init(struct ceph_osd_request *osd_req, unsigned int which, u16 opcode, const char *name, const void *value, size_t size, u8 cmp_op, u8 cmp_mode) { - struct ceph_osd_req_op *op = _osd_req_op_init(osd_req, which, opcode); + struct ceph_osd_req_op *op = _osd_req_op_init(osd_req, which, + opcode, 0); struct ceph_pagelist *pagelist; size_t payload_len; @@ -588,7 +592,8 @@ void osd_req_op_watch_init(struct ceph_osd_request *osd_req, unsigned int which, u16 opcode, u64 cookie, u64 version, int flag) { - struct ceph_osd_req_op *op = _osd_req_op_init(osd_req, which, opcode); + struct ceph_osd_req_op *op = _osd_req_op_init(osd_req, which, + opcode, 0); BUG_ON(opcode != CEPH_OSD_OP_NOTIFY_ACK && opcode != CEPH_OSD_OP_WATCH); @@ -605,7 +610,8 @@ void osd_req_op_alloc_hint_init(struct ceph_osd_request *osd_req, u64 expected_write_size) { struct ceph_osd_req_op *op = _osd_req_op_init(osd_req, which, - CEPH_OSD_OP_SETALLOCHINT); + CEPH_OSD_OP_SETALLOCHINT, + 0); op->alloc_hint.expected_object_size = expected_object_size; op->alloc_hint.expected_write_size = expected_write_size; @@ -789,7 +795,7 @@ struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *osdc, } if (opcode == CEPH_OSD_OP_CREATE || opcode == CEPH_OSD_OP_DELETE) { - osd_req_op_init(req, which, opcode); + osd_req_op_init(req, which, opcode, 0); } else { u32 object_size = le32_to_cpu(layout->fl_object_size); u32 object_base = off - objoff; -- cgit v1.2.3-70-g09d2 From a319bf56a617354e62cf5f774d2ca4e1a8a3bff3 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Fri, 15 May 2015 12:02:17 +0300 Subject: libceph: store timeouts in jiffies, verify user input There are currently three libceph-level timeouts that the user can specify on mount: mount_timeout, osd_idle_ttl and osdkeepalive. All of these are in seconds and no checking is done on user input: negative values are accepted, we multiply them all by HZ which may or may not overflow, arbitrarily large jiffies then get added together, etc. There is also a bug in the way mount_timeout=0 is handled. It's supposed to mean "infinite timeout", but that's not how wait.h APIs treat it and so __ceph_open_session() for example will busy loop without much chance of being interrupted if none of ceph-mons are there. Fix all this by verifying user input, storing timeouts capped by msecs_to_jiffies() in jiffies and using the new ceph_timeout_jiffies() helper for all user-specified waits to handle infinite timeouts correctly. Signed-off-by: Ilya Dryomov Reviewed-by: Alex Elder --- drivers/block/rbd.c | 5 +++-- fs/ceph/dir.c | 4 ++-- fs/ceph/mds_client.c | 12 ++++++------ fs/ceph/mds_client.h | 2 +- fs/ceph/super.c | 2 +- include/linux/ceph/libceph.h | 17 +++++++++++------ net/ceph/ceph_common.c | 41 +++++++++++++++++++++++++++++++---------- net/ceph/mon_client.c | 11 +++++++++-- net/ceph/osd_client.c | 15 +++++++-------- 9 files changed, 71 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 349115ae3bc2..992683b6b299 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -4963,8 +4963,8 @@ out_err: */ static int rbd_add_get_pool_id(struct rbd_client *rbdc, const char *pool_name) { + struct ceph_options *opts = rbdc->client->options; u64 newest_epoch; - unsigned long timeout = rbdc->client->options->mount_timeout * HZ; int tries = 0; int ret; @@ -4979,7 +4979,8 @@ again: if (rbdc->client->osdc.osdmap->epoch < newest_epoch) { ceph_monc_request_next_osdmap(&rbdc->client->monc); (void) ceph_monc_wait_osdmap(&rbdc->client->monc, - newest_epoch, timeout); + newest_epoch, + opts->mount_timeout); goto again; } else { /* the osdmap we have is new enough */ diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 4248307fea90..173dd4b58c71 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -1259,8 +1259,8 @@ static int ceph_dir_fsync(struct file *file, loff_t start, loff_t end, inode, req->r_tid, last_tid); if (req->r_timeout) { unsigned long time_left = wait_for_completion_timeout( - &req->r_safe_completion, - req->r_timeout); + &req->r_safe_completion, + ceph_timeout_jiffies(req->r_timeout)); if (time_left > 0) ret = 0; else diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 69a36f40517f..0b0e0a9a81c0 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -2268,7 +2268,8 @@ int ceph_mdsc_do_request(struct ceph_mds_client *mdsc, dout("do_request waiting\n"); if (req->r_timeout) { err = (long)wait_for_completion_killable_timeout( - &req->r_completion, req->r_timeout); + &req->r_completion, + ceph_timeout_jiffies(req->r_timeout)); if (err == 0) err = -EIO; } else if (req->r_wait_for_completion) { @@ -3424,8 +3425,8 @@ int ceph_mdsc_init(struct ceph_fs_client *fsc) */ static void wait_requests(struct ceph_mds_client *mdsc) { + struct ceph_options *opts = mdsc->fsc->client->options; struct ceph_mds_request *req; - struct ceph_fs_client *fsc = mdsc->fsc; mutex_lock(&mdsc->mutex); if (__get_oldest_req(mdsc)) { @@ -3433,7 +3434,7 @@ static void wait_requests(struct ceph_mds_client *mdsc) dout("wait_requests waiting for requests\n"); wait_for_completion_timeout(&mdsc->safe_umount_waiters, - fsc->client->options->mount_timeout * HZ); + ceph_timeout_jiffies(opts->mount_timeout)); /* tear down remaining requests */ mutex_lock(&mdsc->mutex); @@ -3556,10 +3557,9 @@ static bool done_closing_sessions(struct ceph_mds_client *mdsc) */ void ceph_mdsc_close_sessions(struct ceph_mds_client *mdsc) { + struct ceph_options *opts = mdsc->fsc->client->options; struct ceph_mds_session *session; int i; - struct ceph_fs_client *fsc = mdsc->fsc; - unsigned long timeout = fsc->client->options->mount_timeout * HZ; dout("close_sessions\n"); @@ -3580,7 +3580,7 @@ void ceph_mdsc_close_sessions(struct ceph_mds_client *mdsc) dout("waiting for sessions to close\n"); wait_event_timeout(mdsc->session_close_wq, done_closing_sessions(mdsc), - timeout); + ceph_timeout_jiffies(opts->mount_timeout)); /* tear down remaining sessions */ mutex_lock(&mdsc->mutex); diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h index 2ef799961ebb..509d6822e9b1 100644 --- a/fs/ceph/mds_client.h +++ b/fs/ceph/mds_client.h @@ -227,7 +227,7 @@ struct ceph_mds_request { int r_err; bool r_aborted; - unsigned long r_timeout; /* optional. jiffies */ + unsigned long r_timeout; /* optional. jiffies, 0 is "wait forever" */ unsigned long r_started; /* start time to measure timeout against */ unsigned long r_request_started; /* start time for mds request only, used to measure lease durations */ diff --git a/fs/ceph/super.c b/fs/ceph/super.c index 9a5350030af8..edeb83c43112 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -742,7 +742,7 @@ static struct dentry *open_root_dentry(struct ceph_fs_client *fsc, req->r_ino1.ino = CEPH_INO_ROOT; req->r_ino1.snap = CEPH_NOSNAP; req->r_started = started; - req->r_timeout = fsc->client->options->mount_timeout * HZ; + req->r_timeout = fsc->client->options->mount_timeout; req->r_args.getattr.mask = cpu_to_le32(CEPH_STAT_CAP_INODE); req->r_num_caps = 2; err = ceph_mdsc_do_request(mdsc, NULL, req); diff --git a/include/linux/ceph/libceph.h b/include/linux/ceph/libceph.h index 85ae9a889a3f..d73a569f9bf5 100644 --- a/include/linux/ceph/libceph.h +++ b/include/linux/ceph/libceph.h @@ -43,9 +43,9 @@ struct ceph_options { int flags; struct ceph_fsid fsid; struct ceph_entity_addr my_addr; - int mount_timeout; - int osd_idle_ttl; - int osd_keepalive_timeout; + unsigned long mount_timeout; /* jiffies */ + unsigned long osd_idle_ttl; /* jiffies */ + unsigned long osd_keepalive_timeout; /* jiffies */ /* * any type that can't be simply compared or doesn't need need @@ -63,9 +63,9 @@ struct ceph_options { /* * defaults */ -#define CEPH_MOUNT_TIMEOUT_DEFAULT 60 -#define CEPH_OSD_KEEPALIVE_DEFAULT 5 -#define CEPH_OSD_IDLE_TTL_DEFAULT 60 +#define CEPH_MOUNT_TIMEOUT_DEFAULT msecs_to_jiffies(60 * 1000) +#define CEPH_OSD_KEEPALIVE_DEFAULT msecs_to_jiffies(5 * 1000) +#define CEPH_OSD_IDLE_TTL_DEFAULT msecs_to_jiffies(60 * 1000) #define CEPH_MSG_MAX_FRONT_LEN (16*1024*1024) #define CEPH_MSG_MAX_MIDDLE_LEN (16*1024*1024) @@ -93,6 +93,11 @@ enum { CEPH_MOUNT_SHUTDOWN, }; +static inline unsigned long ceph_timeout_jiffies(unsigned long timeout) +{ + return timeout ?: MAX_SCHEDULE_TIMEOUT; +} + struct ceph_mds_client; /* diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c index 79e8f71aef5b..a80e91c2c9a3 100644 --- a/net/ceph/ceph_common.c +++ b/net/ceph/ceph_common.c @@ -352,8 +352,8 @@ ceph_parse_options(char *options, const char *dev_name, /* start with defaults */ opt->flags = CEPH_OPT_DEFAULT; opt->osd_keepalive_timeout = CEPH_OSD_KEEPALIVE_DEFAULT; - opt->mount_timeout = CEPH_MOUNT_TIMEOUT_DEFAULT; /* seconds */ - opt->osd_idle_ttl = CEPH_OSD_IDLE_TTL_DEFAULT; /* seconds */ + opt->mount_timeout = CEPH_MOUNT_TIMEOUT_DEFAULT; + opt->osd_idle_ttl = CEPH_OSD_IDLE_TTL_DEFAULT; /* get mon ip(s) */ /* ip1[:port1][,ip2[:port2]...] */ @@ -439,13 +439,32 @@ ceph_parse_options(char *options, const char *dev_name, pr_warn("ignoring deprecated osdtimeout option\n"); break; case Opt_osdkeepalivetimeout: - opt->osd_keepalive_timeout = intval; + /* 0 isn't well defined right now, reject it */ + if (intval < 1 || intval > INT_MAX / 1000) { + pr_err("osdkeepalive out of range\n"); + err = -EINVAL; + goto out; + } + opt->osd_keepalive_timeout = + msecs_to_jiffies(intval * 1000); break; case Opt_osd_idle_ttl: - opt->osd_idle_ttl = intval; + /* 0 isn't well defined right now, reject it */ + if (intval < 1 || intval > INT_MAX / 1000) { + pr_err("osd_idle_ttl out of range\n"); + err = -EINVAL; + goto out; + } + opt->osd_idle_ttl = msecs_to_jiffies(intval * 1000); break; case Opt_mount_timeout: - opt->mount_timeout = intval; + /* 0 is "wait forever" (i.e. infinite timeout) */ + if (intval < 0 || intval > INT_MAX / 1000) { + pr_err("mount_timeout out of range\n"); + err = -EINVAL; + goto out; + } + opt->mount_timeout = msecs_to_jiffies(intval * 1000); break; case Opt_share: @@ -512,12 +531,14 @@ int ceph_print_client_options(struct seq_file *m, struct ceph_client *client) seq_puts(m, "notcp_nodelay,"); if (opt->mount_timeout != CEPH_MOUNT_TIMEOUT_DEFAULT) - seq_printf(m, "mount_timeout=%d,", opt->mount_timeout); + seq_printf(m, "mount_timeout=%d,", + jiffies_to_msecs(opt->mount_timeout) / 1000); if (opt->osd_idle_ttl != CEPH_OSD_IDLE_TTL_DEFAULT) - seq_printf(m, "osd_idle_ttl=%d,", opt->osd_idle_ttl); + seq_printf(m, "osd_idle_ttl=%d,", + jiffies_to_msecs(opt->osd_idle_ttl) / 1000); if (opt->osd_keepalive_timeout != CEPH_OSD_KEEPALIVE_DEFAULT) seq_printf(m, "osdkeepalivetimeout=%d,", - opt->osd_keepalive_timeout); + jiffies_to_msecs(opt->osd_keepalive_timeout) / 1000); /* drop redundant comma */ if (m->count != pos) @@ -627,7 +648,7 @@ static int have_mon_and_osd_map(struct ceph_client *client) int __ceph_open_session(struct ceph_client *client, unsigned long started) { int err; - unsigned long timeout = client->options->mount_timeout * HZ; + unsigned long timeout = client->options->mount_timeout; /* open session, and wait for mon and osd maps */ err = ceph_monc_open_session(&client->monc); @@ -643,7 +664,7 @@ int __ceph_open_session(struct ceph_client *client, unsigned long started) dout("mount waiting for mon_map\n"); err = wait_event_interruptible_timeout(client->auth_wq, have_mon_and_osd_map(client) || (client->auth_err < 0), - timeout); + ceph_timeout_jiffies(timeout)); if (err == -EINTR || err == -ERESTARTSYS) return err; if (client->auth_err < 0) diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c index 2b3cf05e87b0..0da3bdc116f7 100644 --- a/net/ceph/mon_client.c +++ b/net/ceph/mon_client.c @@ -298,6 +298,12 @@ void ceph_monc_request_next_osdmap(struct ceph_mon_client *monc) } EXPORT_SYMBOL(ceph_monc_request_next_osdmap); +/* + * Wait for an osdmap with a given epoch. + * + * @epoch: epoch to wait for + * @timeout: in jiffies, 0 means "wait forever" + */ int ceph_monc_wait_osdmap(struct ceph_mon_client *monc, u32 epoch, unsigned long timeout) { @@ -308,11 +314,12 @@ int ceph_monc_wait_osdmap(struct ceph_mon_client *monc, u32 epoch, while (monc->have_osdmap < epoch) { mutex_unlock(&monc->mutex); - if (timeout != 0 && time_after_eq(jiffies, started + timeout)) + if (timeout && time_after_eq(jiffies, started + timeout)) return -ETIMEDOUT; ret = wait_event_interruptible_timeout(monc->client->auth_wq, - monc->have_osdmap >= epoch, timeout); + monc->have_osdmap >= epoch, + ceph_timeout_jiffies(timeout)); if (ret < 0) return ret; diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 4cb4fab46e4f..50033677c0fa 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -1097,7 +1097,7 @@ static void __move_osd_to_lru(struct ceph_osd_client *osdc, BUG_ON(!list_empty(&osd->o_osd_lru)); list_add_tail(&osd->o_osd_lru, &osdc->osd_lru); - osd->lru_ttl = jiffies + osdc->client->options->osd_idle_ttl * HZ; + osd->lru_ttl = jiffies + osdc->client->options->osd_idle_ttl; } static void maybe_move_osd_to_lru(struct ceph_osd_client *osdc, @@ -1208,7 +1208,7 @@ static struct ceph_osd *__lookup_osd(struct ceph_osd_client *osdc, int o) static void __schedule_osd_timeout(struct ceph_osd_client *osdc) { schedule_delayed_work(&osdc->timeout_work, - osdc->client->options->osd_keepalive_timeout * HZ); + osdc->client->options->osd_keepalive_timeout); } static void __cancel_osd_timeout(struct ceph_osd_client *osdc) @@ -1576,10 +1576,9 @@ static void handle_timeout(struct work_struct *work) { struct ceph_osd_client *osdc = container_of(work, struct ceph_osd_client, timeout_work.work); + struct ceph_options *opts = osdc->client->options; struct ceph_osd_request *req; struct ceph_osd *osd; - unsigned long keepalive = - osdc->client->options->osd_keepalive_timeout * HZ; struct list_head slow_osds; dout("timeout\n"); down_read(&osdc->map_sem); @@ -1595,7 +1594,8 @@ static void handle_timeout(struct work_struct *work) */ INIT_LIST_HEAD(&slow_osds); list_for_each_entry(req, &osdc->req_lru, r_req_lru_item) { - if (time_before(jiffies, req->r_stamp + keepalive)) + if (time_before(jiffies, + req->r_stamp + opts->osd_keepalive_timeout)) break; osd = req->r_osd; @@ -1622,8 +1622,7 @@ static void handle_osds_timeout(struct work_struct *work) struct ceph_osd_client *osdc = container_of(work, struct ceph_osd_client, osds_timeout_work.work); - unsigned long delay = - osdc->client->options->osd_idle_ttl * HZ >> 2; + unsigned long delay = osdc->client->options->osd_idle_ttl / 4; dout("osds timeout\n"); down_read(&osdc->map_sem); @@ -2628,7 +2627,7 @@ int ceph_osdc_init(struct ceph_osd_client *osdc, struct ceph_client *client) osdc->event_count = 0; schedule_delayed_work(&osdc->osds_timeout_work, - round_jiffies_relative(osdc->client->options->osd_idle_ttl * HZ)); + round_jiffies_relative(osdc->client->options->osd_idle_ttl)); err = -ENOMEM; osdc->req_mempool = mempool_create_kmalloc_pool(10, -- cgit v1.2.3-70-g09d2 From 2894e1d769743eb583bf8dc6be149f64a7c6a798 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Tue, 12 May 2015 19:53:24 +0300 Subject: rbd: timeout watch teardown on unmap with mount_timeout As part of unmap sequence, kernel client has to talk to the OSDs to teardown watch on the header object. If none of the OSDs are available it would hang forever, until interrupted by a signal - when that happens we follow through with the rest of unmap procedure (i.e. unregister the device and put all the data structures) and the unmap is still considired successful (rbd cli tool exits with 0). The watch on the userspace side should eventually timeout so that's fine. This isn't very nice, because various userspace tools (pacemaker rbd resource agent, for example) then have to worry about setting up their own timeouts. Timeout it with mount_timeout (60 seconds by default). Signed-off-by: Ilya Dryomov Reviewed-by: Alex Elder Reviewed-by: Sage Weil --- drivers/block/rbd.c | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 992683b6b299..89fe8a4bc02e 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -1563,22 +1563,39 @@ static void rbd_obj_request_end(struct rbd_obj_request *obj_request) /* * Wait for an object request to complete. If interrupted, cancel the * underlying osd request. + * + * @timeout: in jiffies, 0 means "wait forever" */ -static int rbd_obj_request_wait(struct rbd_obj_request *obj_request) +static int __rbd_obj_request_wait(struct rbd_obj_request *obj_request, + unsigned long timeout) { - int ret; + long ret; dout("%s %p\n", __func__, obj_request); - - ret = wait_for_completion_interruptible(&obj_request->completion); - if (ret < 0) { - dout("%s %p interrupted\n", __func__, obj_request); + ret = wait_for_completion_interruptible_timeout( + &obj_request->completion, + ceph_timeout_jiffies(timeout)); + if (ret <= 0) { + if (ret == 0) + ret = -ETIMEDOUT; rbd_obj_request_end(obj_request); - return ret; + } else { + ret = 0; } - dout("%s %p done\n", __func__, obj_request); - return 0; + dout("%s %p ret %d\n", __func__, obj_request, (int)ret); + return ret; +} + +static int rbd_obj_request_wait(struct rbd_obj_request *obj_request) +{ + return __rbd_obj_request_wait(obj_request, 0); +} + +static int rbd_obj_request_wait_timeout(struct rbd_obj_request *obj_request, + unsigned long timeout) +{ + return __rbd_obj_request_wait(obj_request, timeout); } static void rbd_img_request_complete(struct rbd_img_request *img_request) @@ -3122,6 +3139,7 @@ static struct rbd_obj_request *rbd_obj_watch_request_helper( bool watch) { struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc; + struct ceph_options *opts = osdc->client->options; struct rbd_obj_request *obj_request; int ret; @@ -3148,7 +3166,7 @@ static struct rbd_obj_request *rbd_obj_watch_request_helper( if (ret) goto out; - ret = rbd_obj_request_wait(obj_request); + ret = rbd_obj_request_wait_timeout(obj_request, opts->mount_timeout); if (ret) goto out; -- cgit v1.2.3-70-g09d2 From d3834fefcfe5610702379d78596337875df2db5b Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Fri, 12 Jun 2015 19:19:02 +0300 Subject: rbd: bump queue_max_segments The default queue_limits::max_segments value (BLK_MAX_SEGMENTS = 128) unnecessarily limits bio sizes to 512k (assuming 4k pages). rbd, being a virtual block device, doesn't have any restrictions on the number of physical segments, so bump max_segments to max_hw_sectors, in theory allowing a sector per segment (although the only case this matters that I can think of is some readv/writev style thing). In practice this is going to give us 1M bios - the number of segments in a bio is limited in bio_get_nr_vecs() by BIO_MAX_PAGES = 256. Note that this doesn't result in any improvement on a typical direct sequential test. This is because on a box with a not too badly fragmented memory the default BLK_MAX_SEGMENTS is enough to see nice rbd object size sized requests. The only difference is the size of bios being merged - 512k vs 1M for something like $ dd if=/dev/zero of=/dev/rbd0 oflag=direct bs=$RBD_OBJ_SIZE $ dd if=/dev/rbd0 iflag=direct of=/dev/null bs=$RBD_OBJ_SIZE Signed-off-by: Ilya Dryomov Reviewed-by: Alex Elder --- drivers/block/rbd.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 89fe8a4bc02e..bc88fbcb9715 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -3791,6 +3791,7 @@ static int rbd_init_disk(struct rbd_device *rbd_dev) /* set io sizes to object size */ segment_size = rbd_obj_bytes(&rbd_dev->header); blk_queue_max_hw_sectors(q, segment_size / SECTOR_SIZE); + blk_queue_max_segments(q, segment_size / SECTOR_SIZE); blk_queue_max_segment_size(q, segment_size); blk_queue_io_min(q, segment_size); blk_queue_io_opt(q, segment_size); -- cgit v1.2.3-70-g09d2 From 210c104c544e5be321fc5b78e74b596d36820332 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Mon, 22 Jun 2015 13:24:48 +0300 Subject: rbd: terminate rbd_opts_tokens with Opt_err Also nuke useless Opt_last_bool and don't break lines unnecessarily. Signed-off-by: Ilya Dryomov Reviewed-by: Alex Elder --- drivers/block/rbd.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index bc88fbcb9715..4de8c9167c4b 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -724,7 +724,7 @@ static struct rbd_client *rbd_client_find(struct ceph_options *ceph_opts) } /* - * mount options + * (Per device) rbd map options */ enum { Opt_last_int, @@ -733,8 +733,7 @@ enum { /* string args above */ Opt_read_only, Opt_read_write, - /* Boolean args above */ - Opt_last_bool, + Opt_err }; static match_table_t rbd_opts_tokens = { @@ -744,8 +743,7 @@ static match_table_t rbd_opts_tokens = { {Opt_read_only, "ro"}, /* Alternate spelling */ {Opt_read_write, "read_write"}, {Opt_read_write, "rw"}, /* Alternate spelling */ - /* Boolean args above */ - {-1, NULL} + {Opt_err, NULL} }; struct rbd_options { @@ -761,22 +759,15 @@ static int parse_rbd_opts_token(char *c, void *private) int token, intval, ret; token = match_token(c, rbd_opts_tokens, argstr); - if (token < 0) - return -EINVAL; - if (token < Opt_last_int) { ret = match_int(&argstr[0], &intval); if (ret < 0) { - pr_err("bad mount option arg (not int) " - "at '%s'\n", c); + pr_err("bad mount option arg (not int) at '%s'\n", c); return ret; } dout("got int token %d val %d\n", token, intval); } else if (token > Opt_last_int && token < Opt_last_string) { - dout("got string token %d val %s\n", token, - argstr[0].from); - } else if (token > Opt_last_string && token < Opt_last_bool) { - dout("got Boolean token %d\n", token); + dout("got string token %d val %s\n", token, argstr[0].from); } else { dout("got token %d\n", token); } @@ -789,9 +780,10 @@ static int parse_rbd_opts_token(char *c, void *private) rbd_opts->read_only = false; break; default: - rbd_assert(false); - break; + /* libceph prints "bad option" msg */ + return -EINVAL; } + return 0; } -- cgit v1.2.3-70-g09d2 From d147543d7943eaa549a569143b7815482585fb91 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Mon, 22 Jun 2015 13:24:48 +0300 Subject: rbd: store rbd_options in rbd_device Signed-off-by: Ilya Dryomov Reviewed-by: Alex Elder --- drivers/block/rbd.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 4de8c9167c4b..e502bce02d2c 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -346,6 +346,7 @@ struct rbd_device { struct rbd_image_header header; unsigned long flags; /* possibly lock protected */ struct rbd_spec *spec; + struct rbd_options *opts; char *header_name; @@ -4055,7 +4056,8 @@ static void rbd_spec_free(struct kref *kref) } static struct rbd_device *rbd_dev_create(struct rbd_client *rbdc, - struct rbd_spec *spec) + struct rbd_spec *spec, + struct rbd_options *opts) { struct rbd_device *rbd_dev; @@ -4069,8 +4071,9 @@ static struct rbd_device *rbd_dev_create(struct rbd_client *rbdc, INIT_LIST_HEAD(&rbd_dev->node); init_rwsem(&rbd_dev->header_rwsem); - rbd_dev->spec = spec; rbd_dev->rbd_client = rbdc; + rbd_dev->spec = spec; + rbd_dev->opts = opts; /* Initialize the layout used for all rbd requests */ @@ -4086,6 +4089,7 @@ static void rbd_dev_destroy(struct rbd_device *rbd_dev) { rbd_put_client(rbd_dev->rbd_client); rbd_spec_put(rbd_dev->spec); + kfree(rbd_dev->opts); kfree(rbd_dev); } @@ -5160,7 +5164,7 @@ static int rbd_dev_probe_parent(struct rbd_device *rbd_dev) rbdc = __rbd_get_client(rbd_dev->rbd_client); ret = -ENOMEM; - parent = rbd_dev_create(rbdc, parent_spec); + parent = rbd_dev_create(rbdc, parent_spec, NULL); if (!parent) goto out_err; @@ -5406,9 +5410,6 @@ static ssize_t do_rbd_add(struct bus_type *bus, rc = rbd_add_parse_args(buf, &ceph_opts, &rbd_opts, &spec); if (rc < 0) goto err_out_module; - read_only = rbd_opts->read_only; - kfree(rbd_opts); - rbd_opts = NULL; /* done with this */ rbdc = rbd_get_client(ceph_opts); if (IS_ERR(rbdc)) { @@ -5434,11 +5435,12 @@ static ssize_t do_rbd_add(struct bus_type *bus, goto err_out_client; } - rbd_dev = rbd_dev_create(rbdc, spec); + rbd_dev = rbd_dev_create(rbdc, spec, rbd_opts); if (!rbd_dev) goto err_out_client; rbdc = NULL; /* rbd_dev now owns this */ spec = NULL; /* rbd_dev now owns this */ + rbd_opts = NULL; /* rbd_dev now owns this */ rc = rbd_dev_image_probe(rbd_dev, true); if (rc < 0) @@ -5446,6 +5448,7 @@ static ssize_t do_rbd_add(struct bus_type *bus, /* If we are mapping a snapshot it must be marked read-only */ + read_only = rbd_dev->opts->read_only; if (rbd_dev->spec->snap_id != CEPH_NOSNAP) read_only = true; rbd_dev->mapping.read_only = read_only; @@ -5470,6 +5473,7 @@ err_out_client: rbd_put_client(rbdc); err_out_args: rbd_spec_put(spec); + kfree(rbd_opts); err_out_module: module_put(THIS_MODULE); -- cgit v1.2.3-70-g09d2 From b55841807fb864eccca0167650a65722fd7cd553 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Tue, 23 Jun 2015 16:21:19 +0300 Subject: rbd: queue_depth map option nr_requests (/sys/block/rbd/queue/nr_requests) is pretty much irrelevant in blk-mq case because each driver sets its own max depth that it can handle and that's the number of tags that gets preallocated on setup. Users can't increase queue depth beyond that value via writing to nr_requests. For rbd we are happy with the default BLKDEV_MAX_RQ (128) for most cases but we want to give users the opportunity to increase it. Introduce a new per-device queue_depth option to do just that: $ sudo rbd map -o queue_depth=1024 ... Signed-off-by: Ilya Dryomov Reviewed-by: Alex Elder --- drivers/block/rbd.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index e502bce02d2c..b316ee48a30b 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -728,6 +728,7 @@ static struct rbd_client *rbd_client_find(struct ceph_options *ceph_opts) * (Per device) rbd map options */ enum { + Opt_queue_depth, Opt_last_int, /* int args above */ Opt_last_string, @@ -738,6 +739,7 @@ enum { }; static match_table_t rbd_opts_tokens = { + {Opt_queue_depth, "queue_depth=%d"}, /* int args above */ /* string args above */ {Opt_read_only, "read_only"}, @@ -748,9 +750,11 @@ static match_table_t rbd_opts_tokens = { }; struct rbd_options { + int queue_depth; bool read_only; }; +#define RBD_QUEUE_DEPTH_DEFAULT BLKDEV_MAX_RQ #define RBD_READ_ONLY_DEFAULT false static int parse_rbd_opts_token(char *c, void *private) @@ -774,6 +778,13 @@ static int parse_rbd_opts_token(char *c, void *private) } switch (token) { + case Opt_queue_depth: + if (intval < 1) { + pr_err("queue_depth out of range\n"); + return -EINVAL; + } + rbd_opts->queue_depth = intval; + break; case Opt_read_only: rbd_opts->read_only = true; break; @@ -3761,10 +3772,9 @@ static int rbd_init_disk(struct rbd_device *rbd_dev) memset(&rbd_dev->tag_set, 0, sizeof(rbd_dev->tag_set)); rbd_dev->tag_set.ops = &rbd_mq_ops; - rbd_dev->tag_set.queue_depth = BLKDEV_MAX_RQ; + rbd_dev->tag_set.queue_depth = rbd_dev->opts->queue_depth; rbd_dev->tag_set.numa_node = NUMA_NO_NODE; - rbd_dev->tag_set.flags = - BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_SG_MERGE; + rbd_dev->tag_set.flags = BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_SG_MERGE; rbd_dev->tag_set.nr_hw_queues = 1; rbd_dev->tag_set.cmd_size = sizeof(struct work_struct); @@ -4948,6 +4958,7 @@ static int rbd_add_parse_args(const char *buf, goto out_mem; rbd_opts->read_only = RBD_READ_ONLY_DEFAULT; + rbd_opts->queue_depth = RBD_QUEUE_DEPTH_DEFAULT; copts = ceph_parse_options(options, mon_addrs, mon_addrs + mon_addrs_size - 1, -- cgit v1.2.3-70-g09d2 From 3e2b03dad54bbcab5be948629a644d55ce7b5a2e Mon Sep 17 00:00:00 2001 From: Anshul Garg Date: Thu, 25 Jun 2015 13:33:12 -0700 Subject: Input: use for_each_set_bit() where appropriate Instead of iterating over all bits in a bitmap and test them individually let's siwtch to for_each_set_bit() which is more compact and is also faster. Also use bitmap_weight() when counting number of set bits. This also fixes INPUT_DO_TOGGLE() implementation as it should have used *_CNT as the upper boundary, not *_MAX. Signed-off-by: Anshul Garg Signed-off-by: Dmitry Torokhov --- drivers/input/input.c | 34 +++++++++------------------------- 1 file changed, 9 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/input/input.c b/drivers/input/input.c index f31578423636..78d24990a816 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -677,12 +677,9 @@ static void input_dev_release_keys(struct input_dev *dev) int code; if (is_event_supported(EV_KEY, dev->evbit, EV_MAX)) { - for (code = 0; code <= KEY_MAX; code++) { - if (is_event_supported(code, dev->keybit, KEY_MAX) && - __test_and_clear_bit(code, dev->key)) { - input_pass_event(dev, EV_KEY, code, 0); - } - } + for_each_set_bit(code, dev->key, KEY_CNT) + input_pass_event(dev, EV_KEY, code, 0); + memset(dev->key, 0, sizeof(dev->key)); input_pass_event(dev, EV_SYN, SYN_REPORT, 1); } } @@ -1626,10 +1623,7 @@ static int input_dev_uevent(struct device *device, struct kobj_uevent_env *env) if (!test_bit(EV_##type, dev->evbit)) \ break; \ \ - for (i = 0; i < type##_MAX; i++) { \ - if (!test_bit(i, dev->bits##bit)) \ - continue; \ - \ + for_each_set_bit(i, dev->bits##bit, type##_CNT) { \ active = test_bit(i, dev->bits); \ if (!active && !on) \ continue; \ @@ -1980,22 +1974,12 @@ static unsigned int input_estimate_events_per_packet(struct input_dev *dev) events = mt_slots + 1; /* count SYN_MT_REPORT and SYN_REPORT */ - if (test_bit(EV_ABS, dev->evbit)) { - for (i = 0; i < ABS_CNT; i++) { - if (test_bit(i, dev->absbit)) { - if (input_is_mt_axis(i)) - events += mt_slots; - else - events++; - } - } - } + if (test_bit(EV_ABS, dev->evbit)) + for_each_set_bit(i, dev->absbit, ABS_CNT) + events += input_is_mt_axis(i) ? mt_slots : 1; - if (test_bit(EV_REL, dev->evbit)) { - for (i = 0; i < REL_CNT; i++) - if (test_bit(i, dev->relbit)) - events++; - } + if (test_bit(EV_REL, dev->evbit)) + events += bitmap_weight(dev->relbit, REL_CNT); /* Make room for KEY and MSC events */ events += 7; -- cgit v1.2.3-70-g09d2 From 38e1b72bd8a1de4d7adb6a7cea88174e412cf4d7 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 1 Jun 2015 10:41:11 -0700 Subject: Input: edt-ft5x06 - mark as direct input device edt-ft5x06 is a touchscreen and thus a direct input device; let's amrk it as such. This also allows us to drop some initialization code as input_init_mt_slots() will do that for us. Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/edt-ft5x06.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index e6aef3e48bd9..29d179a1953b 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -1035,11 +1035,6 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, input->id.bustype = BUS_I2C; input->dev.parent = &client->dev; - __set_bit(EV_KEY, input->evbit); - __set_bit(EV_ABS, input->evbit); - __set_bit(BTN_TOUCH, input->keybit); - input_set_abs_params(input, ABS_X, 0, tsdata->num_x * 64 - 1, 0, 0); - input_set_abs_params(input, ABS_Y, 0, tsdata->num_y * 64 - 1, 0, 0); input_set_abs_params(input, ABS_MT_POSITION_X, 0, tsdata->num_x * 64 - 1, 0, 0); input_set_abs_params(input, ABS_MT_POSITION_Y, @@ -1048,7 +1043,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, if (!pdata) touchscreen_parse_of_params(input); - error = input_mt_init_slots(input, MAX_SUPPORT_POINTS, 0); + error = input_mt_init_slots(input, MAX_SUPPORT_POINTS, INPUT_MT_DIRECT); if (error) { dev_err(&client->dev, "Unable to init MT slots.\n"); return error; -- cgit v1.2.3-70-g09d2 From 7c494375b773497228502133879072a9e959c063 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 1 Jun 2015 10:35:16 -0700 Subject: Input: improve parsing OF parameters for touchscreens When applying touchscreen parameters specified in device tree let's make sure we keep whatever setup was done by the driver and not reset the missing values to zero. Reported-by: Pavel Machek Tested-by: Pavel Machek Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/edt-ft5x06.c | 2 +- drivers/input/touchscreen/of_touchscreen.c | 69 +++++++++++++++++++----------- drivers/input/touchscreen/tsc2005.c | 2 +- include/linux/input/touchscreen.h | 5 ++- 4 files changed, 49 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 29d179a1953b..394b1de9a2a3 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -1041,7 +1041,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, 0, tsdata->num_y * 64 - 1, 0, 0); if (!pdata) - touchscreen_parse_of_params(input); + touchscreen_parse_of_params(input, true); error = input_mt_init_slots(input, MAX_SUPPORT_POINTS, INPUT_MT_DIRECT); if (error) { diff --git a/drivers/input/touchscreen/of_touchscreen.c b/drivers/input/touchscreen/of_touchscreen.c index b82b5207c78b..806cd0ad160f 100644 --- a/drivers/input/touchscreen/of_touchscreen.c +++ b/drivers/input/touchscreen/of_touchscreen.c @@ -14,14 +14,22 @@ #include #include -static u32 of_get_optional_u32(struct device_node *np, - const char *property) +static bool touchscreen_get_prop_u32(struct device_node *np, + const char *property, + unsigned int default_value, + unsigned int *value) { - u32 val = 0; + u32 val; + int error; - of_property_read_u32(np, property, &val); + error = of_property_read_u32(np, property, &val); + if (error) { + *value = default_value; + return false; + } - return val; + *value = val; + return true; } static void touchscreen_set_params(struct input_dev *dev, @@ -54,34 +62,45 @@ static void touchscreen_set_params(struct input_dev *dev, * input device accordingly. The function keeps previously setuped default * values if no value is specified via DT. */ -void touchscreen_parse_of_params(struct input_dev *dev) +void touchscreen_parse_of_params(struct input_dev *dev, bool multitouch) { struct device_node *np = dev->dev.parent->of_node; - u32 maximum, fuzz; + unsigned int axis; + unsigned int maximum, fuzz; + bool data_present; input_alloc_absinfo(dev); if (!dev->absinfo) return; - maximum = of_get_optional_u32(np, "touchscreen-size-x"); - fuzz = of_get_optional_u32(np, "touchscreen-fuzz-x"); - if (maximum || fuzz) { - touchscreen_set_params(dev, ABS_X, maximum, fuzz); - touchscreen_set_params(dev, ABS_MT_POSITION_X, maximum, fuzz); - } + axis = multitouch ? ABS_MT_POSITION_X : ABS_X; + data_present = touchscreen_get_prop_u32(np, "touchscreen-size-x", + input_abs_get_max(dev, axis), + &maximum) | + touchscreen_get_prop_u32(np, "touchscreen-fuzz-x", + input_abs_get_fuzz(dev, axis), + &fuzz); + if (data_present) + touchscreen_set_params(dev, axis, maximum, fuzz); - maximum = of_get_optional_u32(np, "touchscreen-size-y"); - fuzz = of_get_optional_u32(np, "touchscreen-fuzz-y"); - if (maximum || fuzz) { - touchscreen_set_params(dev, ABS_Y, maximum, fuzz); - touchscreen_set_params(dev, ABS_MT_POSITION_Y, maximum, fuzz); - } + axis = multitouch ? ABS_MT_POSITION_Y : ABS_Y; + data_present = touchscreen_get_prop_u32(np, "touchscreen-size-y", + input_abs_get_max(dev, axis), + &maximum) | + touchscreen_get_prop_u32(np, "touchscreen-fuzz-y", + input_abs_get_fuzz(dev, axis), + &fuzz); + if (data_present) + touchscreen_set_params(dev, axis, maximum, fuzz); - maximum = of_get_optional_u32(np, "touchscreen-max-pressure"); - fuzz = of_get_optional_u32(np, "touchscreen-fuzz-pressure"); - if (maximum || fuzz) { - touchscreen_set_params(dev, ABS_PRESSURE, maximum, fuzz); - touchscreen_set_params(dev, ABS_MT_PRESSURE, maximum, fuzz); - } + axis = multitouch ? ABS_MT_PRESSURE : ABS_PRESSURE; + data_present = touchscreen_get_prop_u32(np, "touchscreen-max-pressure", + input_abs_get_max(dev, axis), + &maximum) | + touchscreen_get_prop_u32(np, "touchscreen-fuzz-pressure", + input_abs_get_fuzz(dev, axis), + &fuzz); + if (data_present) + touchscreen_set_params(dev, axis, maximum, fuzz); } EXPORT_SYMBOL(touchscreen_parse_of_params); diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 72657c579430..d8c025b0f88c 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -709,7 +709,7 @@ static int tsc2005_probe(struct spi_device *spi) input_set_abs_params(input_dev, ABS_PRESSURE, 0, max_p, fudge_p, 0); if (np) - touchscreen_parse_of_params(input_dev); + touchscreen_parse_of_params(input_dev, false); input_dev->open = tsc2005_open; input_dev->close = tsc2005_close; diff --git a/include/linux/input/touchscreen.h b/include/linux/input/touchscreen.h index 08a5ef6e8f25..eecc9ea6cd58 100644 --- a/include/linux/input/touchscreen.h +++ b/include/linux/input/touchscreen.h @@ -12,9 +12,10 @@ #include #ifdef CONFIG_OF -void touchscreen_parse_of_params(struct input_dev *dev); +void touchscreen_parse_of_params(struct input_dev *dev, bool multitouch); #else -static inline void touchscreen_parse_of_params(struct input_dev *dev) +static inline void touchscreen_parse_of_params(struct input_dev *dev, + bool multitouch) { } #endif -- cgit v1.2.3-70-g09d2 From ac88cd738425e04dbed3706621cf613a00708834 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Thu, 28 May 2015 11:07:11 -0700 Subject: drm/i915: Fix IPS related flicker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We cannot let IPS enabled with no plane on the pipe: BSpec: "IPS cannot be enabled until after at least one plane has been enabled for at least one vertical blank." and "IPS must be disabled while there is still at least one plane enabled on the same pipe as IPS." This restriction apply to HSW and BDW. However a shortcut path on update primary plane function to make primary plane invisible by setting DSPCTRL to 0 was leting IPS enabled while there was no other plane enabled on the pipe causing flickerings that we were believing that it was caused by that other restriction where ips cannot be used when pixel rate is greater than 95% of cdclok. v2: Don't mess with Atomic path as pointed out by Ville. Reference: https://bugs.freedesktop.org/show_bug.cgi?id=85583 Cc: Ville Syrjälä Cc: Paulo Zanoni Cc: stable@vger.kernel.org Signed-off-by: Rodrigo Vivi Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 13 +++++++++++++ drivers/gpu/drm/i915/intel_drv.h | 1 + 2 files changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index dcb1d25d6f05..1b61f9810387 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13303,6 +13303,16 @@ intel_check_primary_plane(struct drm_plane *plane, intel_crtc->atomic.wait_vblank = true; } + /* + * FIXME: Actually if we will still have any other plane enabled + * on the pipe we could let IPS enabled still, but for + * now lets consider that when we make primary invisible + * by setting DSPCNTR to 0 on update_primary_plane function + * IPS needs to be disable. + */ + if (!state->visible || !fb) + intel_crtc->atomic.disable_ips = true; + intel_crtc->atomic.fb_bits |= INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe); @@ -13400,6 +13410,9 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc) if (intel_crtc->atomic.disable_fbc) intel_fbc_disable(dev); + if (intel_crtc->atomic.disable_ips) + hsw_disable_ips(intel_crtc); + if (intel_crtc->atomic.pre_disable_primary) intel_pre_disable_primary(crtc); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 2afb31a46275..105928382e21 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -485,6 +485,7 @@ struct intel_crtc_atomic_commit { /* Sleepable operations to perform before commit */ bool wait_for_flips; bool disable_fbc; + bool disable_ips; bool pre_disable_primary; bool update_wm; unsigned disabled_planes; -- cgit v1.2.3-70-g09d2 From 00245266b4be4fbe989ee073663f56716da6c1f3 Mon Sep 17 00:00:00 2001 From: Michel Thierry Date: Thu, 25 Jun 2015 12:59:38 +0100 Subject: drm/i915/ppgtt: Break loop in gen8_ppgtt_clear_range failure path If for some reason [1], the page directory/table does not exist, clear_range would end up in an infinite while loop. Introduced by commit 06fda602dbca ("drm/i915: Create page table allocators"). [1] This is already being addressed in one of Mika's patches: http://mid.gmane.org/1432314314-23530-17-git-send-email-mika.kuoppala@intel.com Cc: Mika Kuoppala Cc: stable@vger.kernel.org Reported-by: John Harrison Signed-off-by: Michel Thierry Reviewed-by: Mika Kuoppala Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_gem_gtt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 619dad1b2386..9daa2883ac18 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -516,17 +516,17 @@ static void gen8_ppgtt_clear_range(struct i915_address_space *vm, struct page *page_table; if (WARN_ON(!ppgtt->pdp.page_directory[pdpe])) - continue; + break; pd = ppgtt->pdp.page_directory[pdpe]; if (WARN_ON(!pd->page_table[pde])) - continue; + break; pt = pd->page_table[pde]; if (WARN_ON(!pt->page)) - continue; + break; page_table = pt->page; -- cgit v1.2.3-70-g09d2 From 0d44b410a01a75daff60ce4cb78313135cdb3649 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 26 Jun 2015 21:21:16 +0200 Subject: tc1100-wmi: Delete an unnecessary check before the function call "kfree" The kfree() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Darren Hart --- drivers/platform/x86/tc1100-wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/tc1100-wmi.c b/drivers/platform/x86/tc1100-wmi.c index e36542564131..89aa976f0ab2 100644 --- a/drivers/platform/x86/tc1100-wmi.c +++ b/drivers/platform/x86/tc1100-wmi.c @@ -82,7 +82,7 @@ static int get_state(u32 *out, u8 instance) tmp = 0; } - if (result.length > 0 && result.pointer) + if (result.length > 0) kfree(result.pointer); switch (instance) { -- cgit v1.2.3-70-g09d2 From 8b572a4200828b4e75cc22ed2f494b58d5372d65 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 28 Jun 2015 14:18:16 +0100 Subject: agp/intel: Fix typo in needs_ilk_vtd_wa() In needs_ilk_vtd_wa(), we pass in the GPU device but compared it against the ids for the mobile GPU and the mobile host bridge. That latter is impossible and so likely was just a typo for the desktop GPU device id (which is also buggy). Fixes commit da88a5f7f7d434e2cde1b3e19d952e6d84533662 Author: Chris Wilson Date: Wed Feb 13 09:31:53 2013 +0000 drm/i915: Disable WC PTE updates to w/a buggy IOMMU on ILK Reported-by: Ting-Wei Lan Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=91127 References: https://bugzilla.freedesktop.org/show_bug.cgi?id=60391 Signed-off-by: Chris Wilson Cc: Daniel Vetter Cc: stable@vger.kernel.org Reviewed-by: Daniel Vetter Signed-off-by: Jani Nikula --- drivers/char/agp/intel-gtt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 0b4188b9af7c..c6dea3f6917b 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -581,7 +581,7 @@ static inline int needs_ilk_vtd_wa(void) /* Query intel_iommu to see if we need the workaround. Presumably that * was loaded first. */ - if ((gpu_devid == PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB || + if ((gpu_devid == PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG || gpu_devid == PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG) && intel_iommu_gfx_mapped) return 1; -- cgit v1.2.3-70-g09d2 From 2059ac3b1304cb6a82f9d90762dea9f556831627 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 26 Jun 2015 14:18:56 +0300 Subject: drm/i915: fix backlight after resume on 855gm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some 855gm models (at least ThinkPad X40) regressed because of commit b0cd324faed23d10d66ba6ade66579c681feef6f Author: Jani Nikula Date: Wed Nov 12 16:25:43 2014 +0200 drm/i915: don't save/restore backlight hist ctl registers which tried to make our driver more robust by not blindly saving and restoring registers, but it failed to take into account commit 0eb96d6ed38430b72897adde58f5477a6b71757a Author: Jesse Barnes Date: Wed Oct 14 12:33:41 2009 -0700 drm/i915: save/restore BLC histogram control reg across suspend/resume Fix the regression by enabling hist ctl on gen2. v2: Improved the comment. v3: Improved the comment, again. Reported-and-tested-by: Philipp Gesang References: http://mid.gmane.org/20150623222648.GD12335@acheron Fixes: b0cd324faed2 ("drm/i915: don't save/restore backlight hist ctl registers") Cc: Ville Syrjälä Cc: stable@vger.kernel.org Acked-by: Chris Wilson Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_panel.c | 8 ++++++++ 2 files changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 6d3fead3a358..47bb110a5e36 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3491,6 +3491,7 @@ enum skl_disp_power_wells { #define BLM_POLARITY_PNV (1 << 0) /* pnv only */ #define BLC_HIST_CTL (dev_priv->info.display_mmio_offset + 0x61260) +#define BLM_HISTOGRAM_ENABLE (1 << 31) /* New registers for PCH-split platforms. Safe where new bits show up, the * register layout machtes with gen4 BLC_PWM_CTL[12]. */ diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 7d83527f95f7..55aad2322e10 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -907,6 +907,14 @@ static void i9xx_enable_backlight(struct intel_connector *connector) /* XXX: combine this into above write? */ intel_panel_actually_set_backlight(connector, panel->backlight.level); + + /* + * Needed to enable backlight on some 855gm models. BLC_HIST_CTL is + * 855gm only, but checking for gen2 is safe, as 855gm is the only gen2 + * that has backlight. + */ + if (IS_GEN2(dev)) + I915_WRITE(BLC_HIST_CTL, BLM_HISTOGRAM_ENABLE); } static void i965_enable_backlight(struct intel_connector *connector) -- cgit v1.2.3-70-g09d2 From e922cfb1c410d8cb200a08f1b2a527d92d95480a Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 11 Jun 2015 11:26:03 -0400 Subject: drm/amdgpu: fix hpd range check in dce_v8_0_hpd_irq() Spotted by Dan Carpenter. This is a slight variant of his fix. Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/dce_v8_0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c index 72c27ac915f2..aaca8d663f2c 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c @@ -3379,7 +3379,7 @@ static int dce_v8_0_hpd_irq(struct amdgpu_device *adev, uint32_t disp_int, mask, int_control, tmp; unsigned hpd; - if (entry->src_data > 6) { + if (entry->src_data >= adev->mode_info.num_hpd) { DRM_DEBUG("Unhandled interrupt: %d %d\n", entry->src_id, entry->src_data); return 0; } -- cgit v1.2.3-70-g09d2 From 69ee2410238e6ea6fd5d0a91b04510bba8abc7b5 Mon Sep 17 00:00:00 2001 From: Maninder Singh Date: Fri, 19 Jun 2015 09:35:23 +0530 Subject: drm/radeon: use kzalloc for allocating one thing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use kzalloc for allocating one thing rather than kcalloc(1... The semantic patch that makes this change is as follows: // @@ @@ - kcalloc(1, + kzalloc( ...) // Signed-off-by: Maninder Singh Reviewed-by: Vaneet Narang Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_ttm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index edafd3c2b170..06ac59fe332a 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -719,7 +719,7 @@ static int radeon_ttm_tt_populate(struct ttm_tt *ttm) return 0; if (gtt && gtt->userptr) { - ttm->sg = kcalloc(1, sizeof(struct sg_table), GFP_KERNEL); + ttm->sg = kzalloc(sizeof(struct sg_table), GFP_KERNEL); if (!ttm->sg) return -ENOMEM; -- cgit v1.2.3-70-g09d2 From cd06bf687b89f7532d19b0e4484299372e1bf70c Mon Sep 17 00:00:00 2001 From: Ben Goz Date: Wed, 24 Jun 2015 22:39:21 +0300 Subject: drm/amdgpu: Initialize compute sdma and memory from kgd v2: add missing MTYPE_NONCACHED enum Signed-off-by: Ben Goz Acked-by: Oded Gabbay Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/cikd.h | 6 +++++ drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c | 42 ++++++++++++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 47 ++++++++++++++++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c | 28 ++++++++++++++++++++ 4 files changed, 123 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/cikd.h b/drivers/gpu/drm/amd/amdgpu/cikd.h index 220865a44814..d19085a97064 100644 --- a/drivers/gpu/drm/amd/amdgpu/cikd.h +++ b/drivers/gpu/drm/amd/amdgpu/cikd.h @@ -552,4 +552,10 @@ #define VCE_CMD_IB_AUTO 0x00000005 #define VCE_CMD_SEMAPHORE 0x00000006 +/* valid for both DEFAULT_MTYPE and APE1_MTYPE */ +enum { + MTYPE_CACHED = 0, + MTYPE_NONCACHED = 3 +}; + #endif diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c index cb7907447b81..2c188fb9fd22 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c @@ -2009,6 +2009,46 @@ static void gfx_v7_0_setup_rb(struct amdgpu_device *adev, mutex_unlock(&adev->grbm_idx_mutex); } +/** + * gmc_v7_0_init_compute_vmid - gart enable + * + * @rdev: amdgpu_device pointer + * + * Initialize compute vmid sh_mem registers + * + */ +#define DEFAULT_SH_MEM_BASES (0x6000) +#define FIRST_COMPUTE_VMID (8) +#define LAST_COMPUTE_VMID (16) +static void gmc_v7_0_init_compute_vmid(struct amdgpu_device *adev) +{ + int i; + uint32_t sh_mem_config; + uint32_t sh_mem_bases; + + /* + * Configure apertures: + * LDS: 0x60000000'00000000 - 0x60000001'00000000 (4GB) + * Scratch: 0x60000001'00000000 - 0x60000002'00000000 (4GB) + * GPUVM: 0x60010000'00000000 - 0x60020000'00000000 (1TB) + */ + sh_mem_bases = DEFAULT_SH_MEM_BASES | (DEFAULT_SH_MEM_BASES << 16); + sh_mem_config = SH_MEM_ALIGNMENT_MODE_UNALIGNED << + SH_MEM_CONFIG__ALIGNMENT_MODE__SHIFT; + sh_mem_config |= MTYPE_NONCACHED << SH_MEM_CONFIG__DEFAULT_MTYPE__SHIFT; + mutex_lock(&adev->srbm_mutex); + for (i = FIRST_COMPUTE_VMID; i < LAST_COMPUTE_VMID; i++) { + cik_srbm_select(adev, 0, 0, 0, i); + /* CP and shaders */ + WREG32(mmSH_MEM_CONFIG, sh_mem_config); + WREG32(mmSH_MEM_APE1_BASE, 1); + WREG32(mmSH_MEM_APE1_LIMIT, 0); + WREG32(mmSH_MEM_BASES, sh_mem_bases); + } + cik_srbm_select(adev, 0, 0, 0, 0); + mutex_unlock(&adev->srbm_mutex); +} + /** * gfx_v7_0_gpu_init - setup the 3D engine * @@ -2230,6 +2270,8 @@ static void gfx_v7_0_gpu_init(struct amdgpu_device *adev) cik_srbm_select(adev, 0, 0, 0, 0); mutex_unlock(&adev->srbm_mutex); + gmc_v7_0_init_compute_vmid(adev); + WREG32(mmSX_DEBUG_1, 0x20); WREG32(mmTA_CNTL_AUX, 0x00010000); diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index 14242bd33363..e4aeb74d2599 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -1894,6 +1894,51 @@ static void gfx_v8_0_setup_rb(struct amdgpu_device *adev, mutex_unlock(&adev->grbm_idx_mutex); } +/** + * gmc_v8_0_init_compute_vmid - gart enable + * + * @rdev: amdgpu_device pointer + * + * Initialize compute vmid sh_mem registers + * + */ +#define DEFAULT_SH_MEM_BASES (0x6000) +#define FIRST_COMPUTE_VMID (8) +#define LAST_COMPUTE_VMID (16) +static void gmc_v8_0_init_compute_vmid(struct amdgpu_device *adev) +{ + int i; + uint32_t sh_mem_config; + uint32_t sh_mem_bases; + + /* + * Configure apertures: + * LDS: 0x60000000'00000000 - 0x60000001'00000000 (4GB) + * Scratch: 0x60000001'00000000 - 0x60000002'00000000 (4GB) + * GPUVM: 0x60010000'00000000 - 0x60020000'00000000 (1TB) + */ + sh_mem_bases = DEFAULT_SH_MEM_BASES | (DEFAULT_SH_MEM_BASES << 16); + + sh_mem_config = SH_MEM_ADDRESS_MODE_HSA64 << + SH_MEM_CONFIG__ADDRESS_MODE__SHIFT | + SH_MEM_ALIGNMENT_MODE_UNALIGNED << + SH_MEM_CONFIG__ALIGNMENT_MODE__SHIFT | + MTYPE_CC << SH_MEM_CONFIG__DEFAULT_MTYPE__SHIFT | + SH_MEM_CONFIG__PRIVATE_ATC_MASK; + + mutex_lock(&adev->srbm_mutex); + for (i = FIRST_COMPUTE_VMID; i < LAST_COMPUTE_VMID; i++) { + vi_srbm_select(adev, 0, 0, 0, i); + /* CP and shaders */ + WREG32(mmSH_MEM_CONFIG, sh_mem_config); + WREG32(mmSH_MEM_APE1_BASE, 1); + WREG32(mmSH_MEM_APE1_LIMIT, 0); + WREG32(mmSH_MEM_BASES, sh_mem_bases); + } + vi_srbm_select(adev, 0, 0, 0, 0); + mutex_unlock(&adev->srbm_mutex); +} + static void gfx_v8_0_gpu_init(struct amdgpu_device *adev) { u32 gb_addr_config; @@ -2113,6 +2158,8 @@ static void gfx_v8_0_gpu_init(struct amdgpu_device *adev) vi_srbm_select(adev, 0, 0, 0, 0); mutex_unlock(&adev->srbm_mutex); + gmc_v8_0_init_compute_vmid(adev); + mutex_lock(&adev->grbm_idx_mutex); /* * making sure that the following register writes will be broadcasted diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c index e3c1fde75363..7bb37b93993f 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c @@ -438,6 +438,31 @@ static void sdma_v3_0_rlc_stop(struct amdgpu_device *adev) /* XXX todo */ } +/** + * sdma_v3_0_ctx_switch_enable - stop the async dma engines context switch + * + * @adev: amdgpu_device pointer + * @enable: enable/disable the DMA MEs context switch. + * + * Halt or unhalt the async dma engines context switch (VI). + */ +static void sdma_v3_0_ctx_switch_enable(struct amdgpu_device *adev, bool enable) +{ + u32 f32_cntl; + int i; + + for (i = 0; i < SDMA_MAX_INSTANCE; i++) { + f32_cntl = RREG32(mmSDMA0_CNTL + sdma_offsets[i]); + if (enable) + f32_cntl = REG_SET_FIELD(f32_cntl, SDMA0_CNTL, + AUTO_CTXSW_ENABLE, 1); + else + f32_cntl = REG_SET_FIELD(f32_cntl, SDMA0_CNTL, + AUTO_CTXSW_ENABLE, 0); + WREG32(mmSDMA0_CNTL + sdma_offsets[i], f32_cntl); + } +} + /** * sdma_v3_0_enable - stop the async dma engines * @@ -648,6 +673,8 @@ static int sdma_v3_0_start(struct amdgpu_device *adev) /* unhalt the MEs */ sdma_v3_0_enable(adev, true); + /* enable sdma ring preemption */ + sdma_v3_0_ctx_switch_enable(adev, true); /* start the gfx rings and rlc compute queues */ r = sdma_v3_0_gfx_resume(adev); @@ -1079,6 +1106,7 @@ static int sdma_v3_0_hw_fini(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; + sdma_v3_0_ctx_switch_enable(adev, false); sdma_v3_0_enable(adev, false); return 0; -- cgit v1.2.3-70-g09d2 From 78ad5cdd21f0d614983fc397338944e797ec70b9 Mon Sep 17 00:00:00 2001 From: Ben Goz Date: Fri, 12 Jun 2015 11:08:58 +0300 Subject: drm/amdgpu: Configure doorbell to maximum slots Signed-off-by: Ben Goz Acked-by: Oded Gabbay Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index e4aeb74d2599..7683d7fd6463 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -3128,7 +3128,7 @@ static int gfx_v8_0_cp_compute_resume(struct amdgpu_device *adev) WREG32(mmCP_MEC_DOORBELL_RANGE_LOWER, AMDGPU_DOORBELL_KIQ << 2); WREG32(mmCP_MEC_DOORBELL_RANGE_UPPER, - AMDGPU_DOORBELL_MEC_RING7 << 2); + 0x7FFFF << 2); } tmp = RREG32(mmCP_HQD_PQ_DOORBELL_CONTROL); tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_DOORBELL_CONTROL, -- cgit v1.2.3-70-g09d2 From 161569deaa03cf3c00ed63352006193f250b0648 Mon Sep 17 00:00:00 2001 From: Jérôme Glisse Date: Fri, 19 Jun 2015 10:32:15 -0400 Subject: drm/radeon: compute ring fix hibernation (CI GPU family) v2. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order for hibernation to reliably work we need to cleanup more thoroughly the compute ring. Hibernation is different from suspend resume as when we resume from hibernation the hardware is first fully initialize by regular kernel then freeze callback happens (which correspond to a suspend inside the radeon kernel driver) and turn off each of the block. It turns out we were not cleanly shutting down the compute ring. This patch fix that. Hibernation and suspend to ram were tested (several times) on : Bonaire Hawaii Mullins Kaveri Kabini Changed since v1: - Factor the ring stop logic into a function taking ring as arg. Cc: stable@vger.kernel.org Signed-off-by: Jérôme Glisse Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/cik.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index b0688b0c8908..4ecf5caa8c6d 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -4604,6 +4604,31 @@ void cik_compute_set_wptr(struct radeon_device *rdev, WDOORBELL32(ring->doorbell_index, ring->wptr); } +static void cik_compute_stop(struct radeon_device *rdev, + struct radeon_ring *ring) +{ + u32 j, tmp; + + cik_srbm_select(rdev, ring->me, ring->pipe, ring->queue, 0); + /* Disable wptr polling. */ + tmp = RREG32(CP_PQ_WPTR_POLL_CNTL); + tmp &= ~WPTR_POLL_EN; + WREG32(CP_PQ_WPTR_POLL_CNTL, tmp); + /* Disable HQD. */ + if (RREG32(CP_HQD_ACTIVE) & 1) { + WREG32(CP_HQD_DEQUEUE_REQUEST, 1); + for (j = 0; j < rdev->usec_timeout; j++) { + if (!(RREG32(CP_HQD_ACTIVE) & 1)) + break; + udelay(1); + } + WREG32(CP_HQD_DEQUEUE_REQUEST, 0); + WREG32(CP_HQD_PQ_RPTR, 0); + WREG32(CP_HQD_PQ_WPTR, 0); + } + cik_srbm_select(rdev, 0, 0, 0, 0); +} + /** * cik_cp_compute_enable - enable/disable the compute CP MEs * @@ -4617,6 +4642,15 @@ static void cik_cp_compute_enable(struct radeon_device *rdev, bool enable) if (enable) WREG32(CP_MEC_CNTL, 0); else { + /* + * To make hibernation reliable we need to clear compute ring + * configuration before halting the compute ring. + */ + mutex_lock(&rdev->srbm_mutex); + cik_compute_stop(rdev,&rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX]); + cik_compute_stop(rdev,&rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX]); + mutex_unlock(&rdev->srbm_mutex); + WREG32(CP_MEC_CNTL, (MEC_ME1_HALT | MEC_ME2_HALT)); rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX].ready = false; rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX].ready = false; -- cgit v1.2.3-70-g09d2 From 2ba8d1bb8f6b589037f7db1f01144fc80750e8f7 Mon Sep 17 00:00:00 2001 From: Jérôme Glisse Date: Fri, 19 Jun 2015 10:32:16 -0400 Subject: drm/radeon: SDMA fix hibernation (CI GPU family). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order for hibernation to reliably work we need to properly turn off the SDMA block, sadly after numerous attemps i haven't not found proper sequence for clean and full shutdown. So simply reset both SDMA block, this makes hibernation works reliably on sea island GPU family (CI) Hibernation and suspend to ram were tested (several times) on : Bonaire Hawaii Mullins Kaveri Kabini Cc: stable@vger.kernel.org Signed-off-by: Jérôme Glisse Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/cik_sdma.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/cik_sdma.c b/drivers/gpu/drm/radeon/cik_sdma.c index f86eb54e7763..d16f2eebd95e 100644 --- a/drivers/gpu/drm/radeon/cik_sdma.c +++ b/drivers/gpu/drm/radeon/cik_sdma.c @@ -268,6 +268,17 @@ static void cik_sdma_gfx_stop(struct radeon_device *rdev) } rdev->ring[R600_RING_TYPE_DMA_INDEX].ready = false; rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX].ready = false; + + /* FIXME use something else than big hammer but after few days can not + * seem to find good combination so reset SDMA blocks as it seems we + * do not shut them down properly. This fix hibernation and does not + * affect suspend to ram. + */ + WREG32(SRBM_SOFT_RESET, SOFT_RESET_SDMA | SOFT_RESET_SDMA1); + (void)RREG32(SRBM_SOFT_RESET); + udelay(50); + WREG32(SRBM_SOFT_RESET, 0); + (void)RREG32(SRBM_SOFT_RESET); } /** -- cgit v1.2.3-70-g09d2 From 344c19f9558d69faec75869b33d558258429bcd9 Mon Sep 17 00:00:00 2001 From: Christian König Date: Tue, 2 Jun 2015 15:47:16 +0200 Subject: drm/amdgpu: simplify fence debugfs output a bit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König Reviewed-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c index 5c9918d01bf9..8f0fc22f6810 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c @@ -1023,7 +1023,7 @@ static int amdgpu_debugfs_fence_info(struct seq_file *m, void *data) amdgpu_fence_process(ring); - seq_printf(m, "--- ring %d ---\n", i); + seq_printf(m, "--- ring %d (%s) ---\n", i, ring->name); seq_printf(m, "Last signaled fence 0x%016llx\n", (unsigned long long)atomic64_read(&ring->fence_drv.last_seq)); seq_printf(m, "Last emitted 0x%016llx\n", @@ -1031,7 +1031,8 @@ static int amdgpu_debugfs_fence_info(struct seq_file *m, void *data) for (j = 0; j < AMDGPU_MAX_RINGS; ++j) { struct amdgpu_ring *other = adev->rings[j]; - if (i != j && other && other->fence_drv.initialized) + if (i != j && other && other->fence_drv.initialized && + ring->fence_drv.sync_seq[j]) seq_printf(m, "Last sync to ring %d 0x%016llx\n", j, ring->fence_drv.sync_seq[j]); } -- cgit v1.2.3-70-g09d2 From 93e3e4385b69d8885e0dd64d1c5b8c351a151e91 Mon Sep 17 00:00:00 2001 From: Christian König Date: Tue, 9 Jun 2015 16:58:33 +0200 Subject: drm/amdgpu: add BO map/unmap trace point MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König Acked-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h | 48 +++++++++++++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 4 +++ 2 files changed, 52 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h index b56dd64bd4ea..9fe4f3ccd319 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h @@ -61,6 +61,54 @@ TRACE_EVENT(amdgpu_vm_grab_id, TP_printk("vmid=%u, ring=%u", __entry->vmid, __entry->ring) ); +TRACE_EVENT(amdgpu_vm_bo_map, + TP_PROTO(struct amdgpu_bo_va *bo_va, + struct amdgpu_bo_va_mapping *mapping), + TP_ARGS(bo_va, mapping), + TP_STRUCT__entry( + __field(struct amdgpu_bo *, bo) + __field(long, start) + __field(long, last) + __field(u64, offset) + __field(u32, flags) + ), + + TP_fast_assign( + __entry->bo = bo_va->bo; + __entry->start = mapping->it.start; + __entry->last = mapping->it.last; + __entry->offset = mapping->offset; + __entry->flags = mapping->flags; + ), + TP_printk("bo=%p, start=%lx, last=%lx, offset=%010llx, flags=%08x", + __entry->bo, __entry->start, __entry->last, + __entry->offset, __entry->flags) +); + +TRACE_EVENT(amdgpu_vm_bo_unmap, + TP_PROTO(struct amdgpu_bo_va *bo_va, + struct amdgpu_bo_va_mapping *mapping), + TP_ARGS(bo_va, mapping), + TP_STRUCT__entry( + __field(struct amdgpu_bo *, bo) + __field(long, start) + __field(long, last) + __field(u64, offset) + __field(u32, flags) + ), + + TP_fast_assign( + __entry->bo = bo_va->bo; + __entry->start = mapping->it.start; + __entry->last = mapping->it.last; + __entry->offset = mapping->offset; + __entry->flags = mapping->flags; + ), + TP_printk("bo=%p, start=%lx, last=%lx, offset=%010llx, flags=%08x", + __entry->bo, __entry->start, __entry->last, + __entry->offset, __entry->flags) +); + TRACE_EVENT(amdgpu_vm_bo_update, TP_PROTO(struct amdgpu_bo_va_mapping *mapping), TP_ARGS(mapping), diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 407882b233c7..9a4e3b63f1cb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -1001,6 +1001,7 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev, list_add(&mapping->list, &bo_va->mappings); interval_tree_insert(&mapping->it, &vm->va); + trace_amdgpu_vm_bo_map(bo_va, mapping); bo_va->addr = 0; @@ -1058,6 +1059,7 @@ error_free: mutex_lock(&vm->mutex); list_del(&mapping->list); interval_tree_remove(&mapping->it, &vm->va); + trace_amdgpu_vm_bo_unmap(bo_va, mapping); kfree(mapping); error_unlock: @@ -1099,6 +1101,7 @@ int amdgpu_vm_bo_unmap(struct amdgpu_device *adev, mutex_lock(&vm->mutex); list_del(&mapping->list); interval_tree_remove(&mapping->it, &vm->va); + trace_amdgpu_vm_bo_unmap(bo_va, mapping); if (bo_va->addr) { /* clear the old address */ @@ -1139,6 +1142,7 @@ void amdgpu_vm_bo_rmv(struct amdgpu_device *adev, list_for_each_entry_safe(mapping, next, &bo_va->mappings, list) { list_del(&mapping->list); interval_tree_remove(&mapping->it, &vm->va); + trace_amdgpu_vm_bo_unmap(bo_va, mapping); if (bo_va->addr) list_add(&mapping->list, &vm->freed); else -- cgit v1.2.3-70-g09d2 From ec74407ac047c150080758f2a4cec47393a6c0f8 Mon Sep 17 00:00:00 2001 From: Christian König Date: Wed, 10 Jun 2015 14:45:21 +0200 Subject: drm/amdgpu: add amdgpu_bo_list_set trace point MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König Acked-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c | 3 +++ drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h | 15 +++++++++++++++ 2 files changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c index 36d34e0afbc3..f82a2dd83874 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c @@ -30,6 +30,7 @@ #include #include "amdgpu.h" +#include "amdgpu_trace.h" static int amdgpu_bo_list_create(struct amdgpu_fpriv *fpriv, struct amdgpu_bo_list **result, @@ -124,6 +125,8 @@ static int amdgpu_bo_list_set(struct amdgpu_device *adev, gws_obj = entry->robj; if (entry->prefered_domains == AMDGPU_GEM_DOMAIN_OA) oa_obj = entry->robj; + + trace_amdgpu_bo_list_set(list, entry->robj); } for (i = 0; i < list->num_entries; ++i) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h index 9fe4f3ccd319..ed20f44b924d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h @@ -169,6 +169,21 @@ TRACE_EVENT(amdgpu_vm_flush, __entry->pd_addr, __entry->ring, __entry->id) ); +TRACE_EVENT(amdgpu_bo_list_set, + TP_PROTO(struct amdgpu_bo_list *list, struct amdgpu_bo *bo), + TP_ARGS(list, bo), + TP_STRUCT__entry( + __field(struct amdgpu_bo_list *, list) + __field(struct amdgpu_bo *, bo) + ), + + TP_fast_assign( + __entry->list = list; + __entry->bo = bo; + ), + TP_printk("list=%p, bo=%p", __entry->list, __entry->bo) +); + DECLARE_EVENT_CLASS(amdgpu_fence_request, TP_PROTO(struct drm_device *dev, int ring, u32 seqno), -- cgit v1.2.3-70-g09d2 From e30590e6e36992a6db28f03409286c164868939f Mon Sep 17 00:00:00 2001 From: Christian König Date: Wed, 10 Jun 2015 19:21:14 +0200 Subject: drm/amdgpu: print the bo_list in the CS trace point as well MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König Acked-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h index ed20f44b924d..961d7265c286 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h @@ -30,19 +30,21 @@ TRACE_EVENT(amdgpu_cs, TP_PROTO(struct amdgpu_cs_parser *p, int i), TP_ARGS(p, i), TP_STRUCT__entry( + __field(struct amdgpu_bo_list *, bo_list) __field(u32, ring) __field(u32, dw) __field(u32, fences) ), TP_fast_assign( + __entry->bo_list = p->bo_list; __entry->ring = p->ibs[i].ring->idx; __entry->dw = p->ibs[i].length_dw; __entry->fences = amdgpu_fence_count_emitted( p->ibs[i].ring); ), - TP_printk("ring=%u, dw=%u, fences=%u", - __entry->ring, __entry->dw, + TP_printk("bo_list=%p, ring=%u, dw=%u, fences=%u", + __entry->bo_list, __entry->ring, __entry->dw, __entry->fences) ); -- cgit v1.2.3-70-g09d2 From 332300b97e700e000739c8db782406b6fd8f092d Mon Sep 17 00:00:00 2001 From: "monk.liu" Date: Mon, 8 Jun 2015 14:48:15 +0800 Subject: drm/amdgpu: fix wrong type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: monk.liu Reviewed-by: Christian König --- drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c index 8f0fc22f6810..f2d885c1da8f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c @@ -522,7 +522,8 @@ long amdgpu_fence_wait_seq_timeout(struct amdgpu_device *adev, u64 *target_seq, { uint64_t last_seq[AMDGPU_MAX_RINGS]; bool signaled; - int i, r; + int i; + long r; if (timeout == 0) { return amdgpu_fence_any_seq_signaled(adev, target_seq); -- cgit v1.2.3-70-g09d2 From 68fdd3df79ee4bff4d63dab920b01d9ed5731115 Mon Sep 17 00:00:00 2001 From: Christian König Date: Tue, 16 Jun 2015 14:50:02 +0200 Subject: drm/amdgpu: silence invalid error message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König Reviewed-by: Leo Liu --- drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index 0ec222295fee..c3ea3635e1fc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -496,7 +496,7 @@ error_unreserve: error_free: drm_free_large(vm_bos); - if (r) + if (r && r != -ERESTARTSYS) DRM_ERROR("Couldn't update BO_VA (%d)\n", r); } -- cgit v1.2.3-70-g09d2 From f1689ec1b0b1256d0e69653cd4aaeee44aafdf5c Mon Sep 17 00:00:00 2001 From: Christian König Date: Thu, 11 Jun 2015 20:56:18 +0200 Subject: drm/amdgpu: check VCE relocation buffer range MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit port of radeon commit 2fc5703abda201f138faf63bdca743d04dbf4b1a. Signed-off-by: Christian König Reviewed-by: Leo Liu --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 1 + drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c | 119 ++++++++++++++++++++++++-------- drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h | 1 - 3 files changed, 92 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 22866d1c3d69..963c4ba5dcba 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -1622,6 +1622,7 @@ struct amdgpu_vce { unsigned fb_version; atomic_t handles[AMDGPU_MAX_VCE_HANDLES]; struct drm_file *filp[AMDGPU_MAX_VCE_HANDLES]; + uint32_t img_size[AMDGPU_MAX_VCE_HANDLES]; struct delayed_work idle_work; const struct firmware *fw; /* VCE firmware */ struct amdgpu_ring ring[AMDGPU_MAX_VCE_RINGS]; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c index 1127a504f118..cb1bff742550 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c @@ -464,10 +464,12 @@ int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle, * @p: parser context * @lo: address of lower dword * @hi: address of higher dword + * @size: minimum size * * Patch relocation inside command stream with real buffer address */ -int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, uint32_t ib_idx, int lo, int hi) +static int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, uint32_t ib_idx, + int lo, int hi, unsigned size) { struct amdgpu_bo_va_mapping *mapping; struct amdgpu_ib *ib = &p->ibs[ib_idx]; @@ -484,6 +486,13 @@ int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, uint32_t ib_idx, int lo, int return -EINVAL; } + if ((addr + (uint64_t)size) > + ((uint64_t)mapping->it.last + 1) * AMDGPU_GPU_PAGE_SIZE) { + DRM_ERROR("BO to small for addr 0x%010Lx %d %d\n", + addr, lo, hi); + return -EINVAL; + } + addr -= ((uint64_t)mapping->it.start) * AMDGPU_GPU_PAGE_SIZE; addr += amdgpu_bo_gpu_offset(bo); @@ -493,6 +502,39 @@ int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, uint32_t ib_idx, int lo, int return 0; } +/** + * amdgpu_vce_validate_handle - validate stream handle + * + * @p: parser context + * @handle: handle to validate + * + * Validates the handle and return the found session index or -EINVAL + * we we don't have another free session index. + */ +static int amdgpu_vce_validate_handle(struct amdgpu_cs_parser *p, + uint32_t handle) +{ + unsigned i; + + /* validate the handle */ + for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) { + if (atomic_read(&p->adev->vce.handles[i]) == handle) + return i; + } + + /* handle not found try to alloc a new one */ + for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) { + if (!atomic_cmpxchg(&p->adev->vce.handles[i], 0, handle)) { + p->adev->vce.filp[i] = p->filp; + p->adev->vce.img_size[i] = 0; + return i; + } + } + + DRM_ERROR("No more free VCE handles!\n"); + return -EINVAL; +} + /** * amdgpu_vce_cs_parse - parse and validate the command stream * @@ -501,10 +543,12 @@ int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, uint32_t ib_idx, int lo, int */ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx) { - uint32_t handle = 0; - bool destroy = false; - int i, r, idx = 0; struct amdgpu_ib *ib = &p->ibs[ib_idx]; + int session_idx = -1; + bool destroyed = false; + uint32_t tmp, handle = 0; + uint32_t *size = &tmp; + int i, r, idx = 0; amdgpu_vce_note_usage(p->adev); @@ -517,13 +561,29 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx) return -EINVAL; } + if (destroyed) { + DRM_ERROR("No other command allowed after destroy!\n"); + return -EINVAL; + } + switch (cmd) { case 0x00000001: // session handle = amdgpu_get_ib_value(p, ib_idx, idx + 2); + session_idx = amdgpu_vce_validate_handle(p, handle); + if (session_idx < 0) + return session_idx; + size = &p->adev->vce.img_size[session_idx]; break; case 0x00000002: // task info + break; + case 0x01000001: // create + *size = amdgpu_get_ib_value(p, ib_idx, idx + 8) * + amdgpu_get_ib_value(p, ib_idx, idx + 10) * + 8 * 3 / 2; + break; + case 0x04000001: // config extension case 0x04000002: // pic control case 0x04000005: // rate control @@ -534,23 +594,39 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx) break; case 0x03000001: // encode - r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 10, idx + 9); + r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 10, idx + 9, + *size); if (r) return r; - r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 12, idx + 11); + r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 12, idx + 11, + *size / 3); if (r) return r; break; case 0x02000001: // destroy - destroy = true; + destroyed = true; break; case 0x05000001: // context buffer + r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2, + *size * 2); + if (r) + return r; + break; + case 0x05000004: // video bitstream buffer + tmp = amdgpu_get_ib_value(p, ib_idx, idx + 4); + r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2, + tmp); + if (r) + return r; + break; + case 0x05000005: // feedback buffer - r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2); + r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2, + 4096); if (r) return r; break; @@ -560,34 +636,21 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx) return -EINVAL; } + if (session_idx == -1) { + DRM_ERROR("no session command at start of IB\n"); + return -EINVAL; + } + idx += len / 4; } - if (destroy) { + if (destroyed) { /* IB contains a destroy msg, free the handle */ for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) atomic_cmpxchg(&p->adev->vce.handles[i], handle, 0); - - return 0; - } - - /* create or encode, validate the handle */ - for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) { - if (atomic_read(&p->adev->vce.handles[i]) == handle) - return 0; - } - - /* handle not found try to alloc a new one */ - for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) { - if (!atomic_cmpxchg(&p->adev->vce.handles[i], 0, handle)) { - p->adev->vce.filp[i] = p->filp; - return 0; - } } - DRM_ERROR("No more free VCE handles!\n"); - - return -EINVAL; + return 0; } /** diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h index b6a9d0956c60..7ccdb5927da5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h @@ -33,7 +33,6 @@ int amdgpu_vce_get_create_msg(struct amdgpu_ring *ring, uint32_t handle, int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle, struct amdgpu_fence **fence); void amdgpu_vce_free_handles(struct amdgpu_device *adev, struct drm_file *filp); -int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, uint32_t ib_idx, int lo, int hi); int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx); bool amdgpu_vce_ring_emit_semaphore(struct amdgpu_ring *ring, struct amdgpu_semaphore *semaphore, -- cgit v1.2.3-70-g09d2 From 2f4b936869e6432a3361217da7e071d4c0c662f6 Mon Sep 17 00:00:00 2001 From: Christian König Date: Thu, 11 Jun 2015 21:33:55 +0200 Subject: drm/amdgpu: make VCE handle check more strict MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Port of radeon commit 29c63fe22a17c64e54016040cd882481bd45ee5a. Signed-off-by: Christian König Reviewed-by: Leo Liu --- drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c | 64 ++++++++++++++++++++++++--------- 1 file changed, 48 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c index cb1bff742550..70181c1da91b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c @@ -507,19 +507,27 @@ static int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, uint32_t ib_idx, * * @p: parser context * @handle: handle to validate + * @allocated: allocated a new handle? * * Validates the handle and return the found session index or -EINVAL * we we don't have another free session index. */ static int amdgpu_vce_validate_handle(struct amdgpu_cs_parser *p, - uint32_t handle) + uint32_t handle, bool *allocated) { unsigned i; + *allocated = false; + /* validate the handle */ for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) { - if (atomic_read(&p->adev->vce.handles[i]) == handle) + if (atomic_read(&p->adev->vce.handles[i]) == handle) { + if (p->adev->vce.filp[i] != p->filp) { + DRM_ERROR("VCE handle collision detected!\n"); + return -EINVAL; + } return i; + } } /* handle not found try to alloc a new one */ @@ -527,6 +535,7 @@ static int amdgpu_vce_validate_handle(struct amdgpu_cs_parser *p, if (!atomic_cmpxchg(&p->adev->vce.handles[i], 0, handle)) { p->adev->vce.filp[i] = p->filp; p->adev->vce.img_size[i] = 0; + *allocated = true; return i; } } @@ -546,9 +555,11 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx) struct amdgpu_ib *ib = &p->ibs[ib_idx]; int session_idx = -1; bool destroyed = false; + bool created = false; + bool allocated = false; uint32_t tmp, handle = 0; uint32_t *size = &tmp; - int i, r, idx = 0; + int i, r = 0, idx = 0; amdgpu_vce_note_usage(p->adev); @@ -558,18 +569,21 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx) if ((len < 8) || (len & 3)) { DRM_ERROR("invalid VCE command length (%d)!\n", len); - return -EINVAL; + r = -EINVAL; + goto out; } if (destroyed) { DRM_ERROR("No other command allowed after destroy!\n"); - return -EINVAL; + r = -EINVAL; + goto out; } switch (cmd) { case 0x00000001: // session handle = amdgpu_get_ib_value(p, ib_idx, idx + 2); - session_idx = amdgpu_vce_validate_handle(p, handle); + session_idx = amdgpu_vce_validate_handle(p, handle, + &allocated); if (session_idx < 0) return session_idx; size = &p->adev->vce.img_size[session_idx]; @@ -579,6 +593,13 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx) break; case 0x01000001: // create + created = true; + if (!allocated) { + DRM_ERROR("Handle already in use!\n"); + r = -EINVAL; + goto out; + } + *size = amdgpu_get_ib_value(p, ib_idx, idx + 8) * amdgpu_get_ib_value(p, ib_idx, idx + 10) * 8 * 3 / 2; @@ -597,12 +618,12 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx) r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 10, idx + 9, *size); if (r) - return r; + goto out; r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 12, idx + 11, *size / 3); if (r) - return r; + goto out; break; case 0x02000001: // destroy @@ -613,7 +634,7 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx) r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2, *size * 2); if (r) - return r; + goto out; break; case 0x05000004: // video bitstream buffer @@ -621,36 +642,47 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx) r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2, tmp); if (r) - return r; + goto out; break; case 0x05000005: // feedback buffer r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2, 4096); if (r) - return r; + goto out; break; default: DRM_ERROR("invalid VCE command (0x%x)!\n", cmd); - return -EINVAL; + r = -EINVAL; + goto out; } if (session_idx == -1) { DRM_ERROR("no session command at start of IB\n"); - return -EINVAL; + r = -EINVAL; + goto out; } idx += len / 4; } - if (destroyed) { - /* IB contains a destroy msg, free the handle */ + if (allocated && !created) { + DRM_ERROR("New session without create command!\n"); + r = -ENOENT; + } + +out: + if ((!r && destroyed) || (r && allocated)) { + /* + * IB contains a destroy msg or we have allocated an + * handle and got an error, anyway free the handle + */ for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) atomic_cmpxchg(&p->adev->vce.handles[i], handle, 0); } - return 0; + return r; } /** -- cgit v1.2.3-70-g09d2 From dc78330a8e07285a26f165242c3a86744ef3ad20 Mon Sep 17 00:00:00 2001 From: Christian König Date: Fri, 12 Jun 2015 14:16:20 +0200 Subject: drm/amdgpu: check VCE feedback and bitstream index MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König Reviewed-by: Leo Liu --- drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c index 70181c1da91b..d3ca73090e39 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c @@ -469,20 +469,24 @@ int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle, * Patch relocation inside command stream with real buffer address */ static int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, uint32_t ib_idx, - int lo, int hi, unsigned size) + int lo, int hi, unsigned size, uint32_t index) { struct amdgpu_bo_va_mapping *mapping; struct amdgpu_ib *ib = &p->ibs[ib_idx]; struct amdgpu_bo *bo; uint64_t addr; + if (index == 0xffffffff) + index = 0; + addr = ((uint64_t)amdgpu_get_ib_value(p, ib_idx, lo)) | ((uint64_t)amdgpu_get_ib_value(p, ib_idx, hi)) << 32; + addr += ((uint64_t)size) * ((uint64_t)index); mapping = amdgpu_cs_find_mapping(p, addr, &bo); if (mapping == NULL) { - DRM_ERROR("Can't find BO for addr 0x%010Lx %d %d\n", - addr, lo, hi); + DRM_ERROR("Can't find BO for addr 0x%010Lx %d %d %d %d\n", + addr, lo, hi, size, index); return -EINVAL; } @@ -495,6 +499,7 @@ static int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, uint32_t ib_idx, addr -= ((uint64_t)mapping->it.start) * AMDGPU_GPU_PAGE_SIZE; addr += amdgpu_bo_gpu_offset(bo); + addr -= ((uint64_t)size) * ((uint64_t)index); ib->ptr[lo] = addr & 0xFFFFFFFF; ib->ptr[hi] = addr >> 32; @@ -553,6 +558,7 @@ static int amdgpu_vce_validate_handle(struct amdgpu_cs_parser *p, int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx) { struct amdgpu_ib *ib = &p->ibs[ib_idx]; + unsigned fb_idx = 0, bs_idx = 0; int session_idx = -1; bool destroyed = false; bool created = false; @@ -590,6 +596,8 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx) break; case 0x00000002: // task info + fb_idx = amdgpu_get_ib_value(p, ib_idx, idx + 6); + bs_idx = amdgpu_get_ib_value(p, ib_idx, idx + 7); break; case 0x01000001: // create @@ -616,12 +624,12 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx) case 0x03000001: // encode r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 10, idx + 9, - *size); + *size, 0); if (r) goto out; r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 12, idx + 11, - *size / 3); + *size / 3, 0); if (r) goto out; break; @@ -632,7 +640,7 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx) case 0x05000001: // context buffer r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2, - *size * 2); + *size * 2, 0); if (r) goto out; break; @@ -640,14 +648,14 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx) case 0x05000004: // video bitstream buffer tmp = amdgpu_get_ib_value(p, ib_idx, idx + 4); r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2, - tmp); + tmp, bs_idx); if (r) goto out; break; case 0x05000005: // feedback buffer r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2, - 4096); + 4096, fb_idx); if (r) goto out; break; -- cgit v1.2.3-70-g09d2 From 845253e78a7871ae87cdc5c135a914c58d6d4f64 Mon Sep 17 00:00:00 2001 From: Sonny Jiang Date: Tue, 23 Jun 2015 11:59:55 -0400 Subject: drm/amdgpu: reset wptr at cp compute resume (v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch is to resolve compute hang at resume time. v2: (agd5f) squash in second fix Signed-off-by: Sonny Jiang Reviewed-by: Christian König --- drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index 7683d7fd6463..7b683fb2173c 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -3144,6 +3144,12 @@ static int gfx_v8_0_cp_compute_resume(struct amdgpu_device *adev) WREG32(mmCP_HQD_PQ_DOORBELL_CONTROL, mqd->cp_hqd_pq_doorbell_control); + /* reset read and write pointers, similar to CP_RB0_WPTR/_RPTR */ + ring->wptr = 0; + mqd->cp_hqd_pq_wptr = ring->wptr; + WREG32(mmCP_HQD_PQ_WPTR, mqd->cp_hqd_pq_wptr); + mqd->cp_hqd_pq_rptr = RREG32(mmCP_HQD_PQ_RPTR); + /* set the vmid for the queue */ mqd->cp_hqd_vmid = 0; WREG32(mmCP_HQD_VMID, mqd->cp_hqd_vmid); -- cgit v1.2.3-70-g09d2 From b8682ac253bdab6c15678f926bdc028b2e5dc0d2 Mon Sep 17 00:00:00 2001 From: Christian König Date: Mon, 22 Jun 2015 14:54:32 +0200 Subject: drm/amdgpu: fix crash on invalid CS IOCTL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König Reviewed-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index f09b2cba40ca..7cd567b268fd 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -445,8 +445,9 @@ static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser, int error, bo for (i = 0; i < parser->nchunks; i++) drm_free_large(parser->chunks[i].kdata); kfree(parser->chunks); - for (i = 0; i < parser->num_ibs; i++) - amdgpu_ib_free(parser->adev, &parser->ibs[i]); + if (parser->ibs) + for (i = 0; i < parser->num_ibs; i++) + amdgpu_ib_free(parser->adev, &parser->ibs[i]); kfree(parser->ibs); if (parser->uf.bo) drm_gem_object_unreference_unlocked(&parser->uf.bo->gem_base); -- cgit v1.2.3-70-g09d2 From 9a5e8fb1c8372ea4b58a76bbb82cb97683bb204b Mon Sep 17 00:00:00 2001 From: Christian König Date: Tue, 23 Jun 2015 17:07:03 +0200 Subject: drm/amdgpu: add chunk id validity check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König Reviewed-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 7cd567b268fd..86b78c799176 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -181,8 +181,6 @@ int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data) } p->chunks[i].chunk_id = user_chunk.chunk_id; p->chunks[i].length_dw = user_chunk.length_dw; - if (p->chunks[i].chunk_id == AMDGPU_CHUNK_ID_IB) - p->num_ibs++; size = p->chunks[i].length_dw; cdata = (void __user *)(unsigned long)user_chunk.chunk_data; @@ -199,7 +197,12 @@ int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data) goto out; } - if (p->chunks[i].chunk_id == AMDGPU_CHUNK_ID_FENCE) { + switch (p->chunks[i].chunk_id) { + case AMDGPU_CHUNK_ID_IB: + p->num_ibs++; + break; + + case AMDGPU_CHUNK_ID_FENCE: size = sizeof(struct drm_amdgpu_cs_chunk_fence); if (p->chunks[i].length_dw * sizeof(uint32_t) >= size) { uint32_t handle; @@ -221,6 +224,11 @@ int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data) r = -EINVAL; goto out; } + break; + + default: + r = -EINVAL; + goto out; } } -- cgit v1.2.3-70-g09d2 From b13e22aeba06aea2acdae657e988c93c22080858 Mon Sep 17 00:00:00 2001 From: Christian König Date: Fri, 26 Jun 2015 12:31:29 +0200 Subject: drm/radeon: fix adding all VAs to the freed list on remove v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We only should do so when the BO_VA was actually mapped. Otherwise we get a nice error message on the next CS. v2: It actually doesn't matter if it was invalidated or not, if it was mapped we need to clear the area where it was mapped. Signed-off-by: Christian König Tested-by: Michel Dänzer (v1) Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_vm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_vm.c b/drivers/gpu/drm/radeon/radeon_vm.c index 9739ded91b7a..618ab5ec8e62 100644 --- a/drivers/gpu/drm/radeon/radeon_vm.c +++ b/drivers/gpu/drm/radeon/radeon_vm.c @@ -1122,12 +1122,12 @@ void radeon_vm_bo_rmv(struct radeon_device *rdev, interval_tree_remove(&bo_va->it, &vm->va); spin_lock(&vm->status_lock); - if (list_empty(&bo_va->vm_status)) { + list_del(&bo_va->vm_status); + if (bo_va->it.start || bo_va->it.last) { bo_va->bo = radeon_bo_ref(bo_va->bo); list_add(&bo_va->vm_status, &vm->freed); } else { radeon_fence_unref(&bo_va->last_pt_update); - list_del(&bo_va->vm_status); kfree(bo_va); } spin_unlock(&vm->status_lock); -- cgit v1.2.3-70-g09d2 From 5f0b34cc72aa627fd28230be3de469321e0af03e Mon Sep 17 00:00:00 2001 From: Maninder Singh Date: Fri, 26 Jun 2015 13:28:50 +0530 Subject: drm/amdgpu: use kzalloc for allocating one thing Use kzalloc rather than kcalloc(1.. for allocating one thing. Signed-off-by: Maninder Singh Reviewed-by: Vaneet Narang Reviewed-by: Christian Konig Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index d3706a498293..dd3415d2e45d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -674,7 +674,7 @@ static int amdgpu_ttm_tt_populate(struct ttm_tt *ttm) return 0; if (gtt && gtt->userptr) { - ttm->sg = kcalloc(1, sizeof(struct sg_table), GFP_KERNEL); + ttm->sg = kzalloc(sizeof(struct sg_table), GFP_KERNEL); if (!ttm->sg) return -ENOMEM; -- cgit v1.2.3-70-g09d2 From a08c1d516fb3eb302ff14a10eedda844e75c625f Mon Sep 17 00:00:00 2001 From: Maninder Singh Date: Fri, 26 Jun 2015 13:26:57 +0530 Subject: drm/amdgpu: remove unnecessary check before kfree kfree(NULL) is safe and this check is probably not required Signed-off-by: Maninder Singh Reviewed-by: Vaneet Narang Reviewed-by: Christian Konig Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index fec487d1c870..a85cd08901a7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -1575,8 +1575,7 @@ void amdgpu_device_fini(struct amdgpu_device *adev) amdgpu_fence_driver_fini(adev); amdgpu_fbdev_fini(adev); r = amdgpu_fini(adev); - if (adev->ip_block_enabled) - kfree(adev->ip_block_enabled); + kfree(adev->ip_block_enabled); adev->ip_block_enabled = NULL; adev->accel_working = false; /* free i2c buses */ -- cgit v1.2.3-70-g09d2 From d8d090b711bc56e095e59f9b536ed3c73c47b36d Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 26 Jun 2015 13:02:57 -0400 Subject: drm/amdgpu: allocate ip_block_enabled memory in common code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove duplication across asic families and make it symmetric with the freeing of the code in amdgpu_device.c Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 4 +++- drivers/gpu/drm/amd/amdgpu/cik.c | 4 ---- drivers/gpu/drm/amd/amdgpu/vi.c | 4 ---- 3 files changed, 3 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index a85cd08901a7..e19097554093 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -1191,7 +1191,9 @@ static int amdgpu_early_init(struct amdgpu_device *adev) return -EINVAL; } - + adev->ip_block_enabled = kcalloc(adev->num_ip_blocks, sizeof(bool), GFP_KERNEL); + if (adev->ip_block_enabled == NULL) + return -ENOMEM; if (adev->ip_blocks == NULL) { DRM_ERROR("No IP blocks found!\n"); diff --git a/drivers/gpu/drm/amd/amdgpu/cik.c b/drivers/gpu/drm/amd/amdgpu/cik.c index 5dab578d6462..341c56681841 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik.c +++ b/drivers/gpu/drm/amd/amdgpu/cik.c @@ -2256,10 +2256,6 @@ int cik_set_ip_blocks(struct amdgpu_device *adev) return -EINVAL; } - adev->ip_block_enabled = kcalloc(adev->num_ip_blocks, sizeof(bool), GFP_KERNEL); - if (adev->ip_block_enabled == NULL) - return -ENOMEM; - return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/vi.c b/drivers/gpu/drm/amd/amdgpu/vi.c index 90fc93c2c1d0..fa5a4448531d 100644 --- a/drivers/gpu/drm/amd/amdgpu/vi.c +++ b/drivers/gpu/drm/amd/amdgpu/vi.c @@ -1189,10 +1189,6 @@ int vi_set_ip_blocks(struct amdgpu_device *adev) return -EINVAL; } - adev->ip_block_enabled = kcalloc(adev->num_ip_blocks, sizeof(bool), GFP_KERNEL); - if (adev->ip_block_enabled == NULL) - return -ENOMEM; - return 0; } -- cgit v1.2.3-70-g09d2 From 966c62fb40610e3cbda7bcd9a0193d8cbb3b77e3 Mon Sep 17 00:00:00 2001 From: Sonny Jiang Date: Fri, 26 Jun 2015 12:26:45 -0400 Subject: drm/amdgpu: correct define SMU_EnabledFeatureScoreboard_SclkDpmOn Signed-off-by: Sonny Jiang Reviewed-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/cz_dpm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/cz_dpm.h b/drivers/gpu/drm/amd/amdgpu/cz_dpm.h index 782a74107664..99e1afc89629 100644 --- a/drivers/gpu/drm/amd/amdgpu/cz_dpm.h +++ b/drivers/gpu/drm/amd/amdgpu/cz_dpm.h @@ -46,7 +46,7 @@ /* Do not change the following, it is also defined in SMU8.h */ #define SMU_EnabledFeatureScoreboard_AcpDpmOn 0x00000001 -#define SMU_EnabledFeatureScoreboard_SclkDpmOn 0x00100000 +#define SMU_EnabledFeatureScoreboard_SclkDpmOn 0x00200000 #define SMU_EnabledFeatureScoreboard_UvdDpmOn 0x00800000 #define SMU_EnabledFeatureScoreboard_VceDpmOn 0x01000000 -- cgit v1.2.3-70-g09d2 From 9dcabece15d16da48bb7c7071306bf6158b42ba3 Mon Sep 17 00:00:00 2001 From: Sonny Jiang Date: Fri, 26 Jun 2015 12:31:46 -0400 Subject: drm/amdgpu: disable enable_nb_ps_policy temporarily Fixes a hang on resume. Signed-off-by: Sonny Jiang Reviewed-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/cz_dpm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/cz_dpm.c b/drivers/gpu/drm/amd/amdgpu/cz_dpm.c index e4936a452bc6..f75a31df30bd 100644 --- a/drivers/gpu/drm/amd/amdgpu/cz_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/cz_dpm.c @@ -425,7 +425,7 @@ static int cz_dpm_init(struct amdgpu_device *adev) pi->mgcg_cgtt_local1 = 0x0; pi->clock_slow_down_step = 25000; pi->skip_clock_slow_down = 1; - pi->enable_nb_ps_policy = 1; + pi->enable_nb_ps_policy = 0; pi->caps_power_containment = true; pi->caps_cac = true; pi->didt_enabled = false; -- cgit v1.2.3-70-g09d2 From ac9134906b3f5c2b45dc80dab0fee792bd516d52 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 29 Jun 2015 11:09:11 -0400 Subject: Revert "drm/radeon: dont switch vt on suspend" This reverts commit b9729b17a414f99c61f4db9ac9f9ed987fa0cbfe. This seems to break the cursor on resume for lots of systems. Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/radeon_fb.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index aeb676708e60..634793ea8418 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -257,7 +257,6 @@ static int radeonfb_create(struct drm_fb_helper *helper, } info->par = rfbdev; - info->skip_vt_switch = true; ret = radeon_framebuffer_init(rdev->ddev, &rfbdev->rfb, &mode_cmd, gobj); if (ret) { -- cgit v1.2.3-70-g09d2 From 7cebc728174424d67df91dfb14f8b6dc13bed993 Mon Sep 17 00:00:00 2001 From: Alexander Kuleshov Date: Sat, 27 Jun 2015 13:16:05 +0600 Subject: gpu/drm/amdgpu: Fix build when CONFIG_DEBUG_FS is not set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the CONFIG_DEBUG_FS is not selected, compilation of the drivers/gpu/drm/amd/amdgpu/amdgpu_device.c provides two warnings that amdgpu_debugfs_regs_init and amdgpu_debugfs_regs_cleanup are used but never defined. And as result: ERROR: "amdgpu_debugfs_regs_cleanup" [drivers/gpu/drm/amd/amdgpu/amdgpu.ko] undefined! ERROR: "amdgpu_debugfs_regs_init" [drivers/gpu/drm/amd/amdgpu/amdgpu.ko] undefined! ^ Reviewed-by: Christian König Signed-off-by: Alexander Kuleshov Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index e19097554093..ba46be361c9b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -2001,4 +2001,10 @@ int amdgpu_debugfs_init(struct drm_minor *minor) void amdgpu_debugfs_cleanup(struct drm_minor *minor) { } +#else +static int amdgpu_debugfs_regs_init(struct amdgpu_device *adev) +{ + return 0; +} +static void amdgpu_debugfs_regs_cleanup(struct amdgpu_device *adev) { } #endif -- cgit v1.2.3-70-g09d2 From 03507c4f2f63d8d98c2455cf4d192589fac553c7 Mon Sep 17 00:00:00 2001 From: Christian König Date: Fri, 19 Jun 2015 17:00:19 +0200 Subject: drm/amdgpu: recreate fence from user seq MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit And use common fence infrastructure for the wait. Signed-off-by: Christian König Reviewed-by: Alex Deucher Reviewed-by: Chunming Zhou --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 5 ++--- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 11 +++++---- drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c | 37 +++++++++++++++++++++++++++++-- 3 files changed, 44 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 963c4ba5dcba..01657830b470 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -425,6 +425,8 @@ int amdgpu_fence_driver_start_ring(struct amdgpu_ring *ring, unsigned irq_type); int amdgpu_fence_emit(struct amdgpu_ring *ring, void *owner, struct amdgpu_fence **fence); +int amdgpu_fence_recreate(struct amdgpu_ring *ring, void *owner, + uint64_t seq, struct amdgpu_fence **fence); void amdgpu_fence_process(struct amdgpu_ring *ring); int amdgpu_fence_wait_next(struct amdgpu_ring *ring); int amdgpu_fence_wait_empty(struct amdgpu_ring *ring); @@ -435,9 +437,6 @@ int amdgpu_fence_wait(struct amdgpu_fence *fence, bool interruptible); int amdgpu_fence_wait_any(struct amdgpu_device *adev, struct amdgpu_fence **fences, bool intr); -long amdgpu_fence_wait_seq_timeout(struct amdgpu_device *adev, - u64 *target_seq, bool intr, - long timeout); struct amdgpu_fence *amdgpu_fence_ref(struct amdgpu_fence *fence); void amdgpu_fence_unref(struct amdgpu_fence **fence); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 86b78c799176..84ba1d1bf327 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -739,9 +739,9 @@ int amdgpu_cs_wait_ioctl(struct drm_device *dev, void *data, { union drm_amdgpu_wait_cs *wait = data; struct amdgpu_device *adev = dev->dev_private; - uint64_t seq[AMDGPU_MAX_RINGS] = {0}; - struct amdgpu_ring *ring = NULL; unsigned long timeout = amdgpu_gem_timeout(wait->in.timeout); + struct amdgpu_fence *fence = NULL; + struct amdgpu_ring *ring = NULL; struct amdgpu_ctx *ctx; long r; @@ -754,9 +754,12 @@ int amdgpu_cs_wait_ioctl(struct drm_device *dev, void *data, if (r) return r; - seq[ring->idx] = wait->in.handle; + r = amdgpu_fence_recreate(ring, filp, wait->in.handle, &fence); + if (r) + return r; - r = amdgpu_fence_wait_seq_timeout(adev, seq, true, timeout); + r = fence_wait_timeout(&fence->base, true, timeout); + amdgpu_fence_unref(&fence); amdgpu_ctx_put(ctx); if (r < 0) return r; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c index f2d885c1da8f..a7189a1fa6a1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c @@ -135,6 +135,38 @@ int amdgpu_fence_emit(struct amdgpu_ring *ring, void *owner, return 0; } +/** + * amdgpu_fence_recreate - recreate a fence from an user fence + * + * @ring: ring the fence is associated with + * @owner: creator of the fence + * @seq: user fence sequence number + * @fence: resulting amdgpu fence object + * + * Recreates a fence command from the user fence sequence number (all asics). + * Returns 0 on success, -ENOMEM on failure. + */ +int amdgpu_fence_recreate(struct amdgpu_ring *ring, void *owner, + uint64_t seq, struct amdgpu_fence **fence) +{ + struct amdgpu_device *adev = ring->adev; + + if (seq > ring->fence_drv.sync_seq[ring->idx]) + return -EINVAL; + + *fence = kmalloc(sizeof(struct amdgpu_fence), GFP_KERNEL); + if ((*fence) == NULL) + return -ENOMEM; + + (*fence)->seq = seq; + (*fence)->ring = ring; + (*fence)->owner = owner; + fence_init(&(*fence)->base, &amdgpu_fence_ops, + &adev->fence_queue.lock, adev->fence_context + ring->idx, + (*fence)->seq); + return 0; +} + /** * amdgpu_fence_check_signaled - callback from fence_queue * @@ -517,8 +549,9 @@ static bool amdgpu_fence_any_seq_signaled(struct amdgpu_device *adev, u64 *seq) * the wait timeout, or an error for all other cases. * -EDEADLK is returned when a GPU lockup has been detected. */ -long amdgpu_fence_wait_seq_timeout(struct amdgpu_device *adev, u64 *target_seq, - bool intr, long timeout) +static long amdgpu_fence_wait_seq_timeout(struct amdgpu_device *adev, + u64 *target_seq, bool intr, + long timeout) { uint64_t last_seq[AMDGPU_MAX_RINGS]; bool signaled; -- cgit v1.2.3-70-g09d2 From 2b48d323b26c37555df3447e11ab9e962eccdc26 Mon Sep 17 00:00:00 2001 From: Christian König Date: Fri, 19 Jun 2015 17:31:29 +0200 Subject: drm/amdgpu: add optional dependencies to the CS IOCTL v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v2: remove unrelated whitespace change, fix C comment Signed-off-by: Christian König Reviewed-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 59 +++++++++++++++++++++++++++++++++- include/uapi/drm/amdgpu_drm.h | 9 ++++++ 2 files changed, 67 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 84ba1d1bf327..d63135bf29c0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -226,6 +226,9 @@ int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data) } break; + case AMDGPU_CHUNK_ID_DEPENDENCIES: + break; + default: r = -EINVAL; goto out; @@ -663,6 +666,55 @@ static int amdgpu_cs_ib_fill(struct amdgpu_device *adev, return 0; } +static int amdgpu_cs_dependencies(struct amdgpu_device *adev, + struct amdgpu_cs_parser *p) +{ + struct amdgpu_ib *ib; + int i, j, r; + + if (!p->num_ibs) + return 0; + + /* Add dependencies to first IB */ + ib = &p->ibs[0]; + for (i = 0; i < p->nchunks; ++i) { + struct drm_amdgpu_cs_chunk_dep *deps; + struct amdgpu_cs_chunk *chunk; + unsigned num_deps; + + chunk = &p->chunks[i]; + + if (chunk->chunk_id != AMDGPU_CHUNK_ID_DEPENDENCIES) + continue; + + deps = (struct drm_amdgpu_cs_chunk_dep *)chunk->kdata; + num_deps = chunk->length_dw * 4 / + sizeof(struct drm_amdgpu_cs_chunk_dep); + + for (j = 0; j < num_deps; ++j) { + struct amdgpu_fence *fence; + struct amdgpu_ring *ring; + + r = amdgpu_cs_get_ring(adev, deps[j].ip_type, + deps[j].ip_instance, + deps[j].ring, &ring); + if (r) + return r; + + r = amdgpu_fence_recreate(ring, p->filp, + deps[j].handle, + &fence); + if (r) + return r; + + amdgpu_sync_fence(&ib->sync, fence); + amdgpu_fence_unref(&fence); + } + } + + return 0; +} + int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) { struct amdgpu_device *adev = dev->dev_private; @@ -697,11 +749,16 @@ int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) else DRM_ERROR("Failed to process the buffer list %d!\n", r); } - } else { + } + + if (!r) { reserved_buffers = true; r = amdgpu_cs_ib_fill(adev, &parser); } + if (!r) + r = amdgpu_cs_dependencies(adev, &parser); + if (r) { amdgpu_cs_parser_fini(&parser, r, reserved_buffers); up_read(&adev->exclusive_lock); diff --git a/include/uapi/drm/amdgpu_drm.h b/include/uapi/drm/amdgpu_drm.h index d3f4832db289..8edf10420361 100644 --- a/include/uapi/drm/amdgpu_drm.h +++ b/include/uapi/drm/amdgpu_drm.h @@ -348,6 +348,7 @@ struct drm_amdgpu_gem_va { #define AMDGPU_CHUNK_ID_IB 0x01 #define AMDGPU_CHUNK_ID_FENCE 0x02 +#define AMDGPU_CHUNK_ID_DEPENDENCIES 0x03 struct drm_amdgpu_cs_chunk { uint32_t chunk_id; @@ -399,6 +400,14 @@ struct drm_amdgpu_cs_chunk_ib { uint32_t ring; }; +struct drm_amdgpu_cs_chunk_dep { + uint32_t ip_type; + uint32_t ip_instance; + uint32_t ring; + uint32_t ctx_id; + uint64_t handle; +}; + struct drm_amdgpu_cs_chunk_fence { uint32_t handle; uint32_t offset; -- cgit v1.2.3-70-g09d2 From fc220f6580be80c36dfba9964b2fd71ceb1d3d97 Mon Sep 17 00:00:00 2001 From: Christian König Date: Mon, 29 Jun 2015 17:12:20 +0200 Subject: drm/amdgpu: add flag to delay VM updates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König Reviewed-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 6 +++--- include/uapi/drm/amdgpu_drm.h | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index c3ea3635e1fc..975edb1000a2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -525,8 +525,8 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, return -EINVAL; } - invalid_flags = ~(AMDGPU_VM_PAGE_READABLE | AMDGPU_VM_PAGE_WRITEABLE | - AMDGPU_VM_PAGE_EXECUTABLE); + invalid_flags = ~(AMDGPU_VM_DELAY_UPDATE | AMDGPU_VM_PAGE_READABLE | + AMDGPU_VM_PAGE_WRITEABLE | AMDGPU_VM_PAGE_EXECUTABLE); if ((args->flags & invalid_flags)) { dev_err(&dev->pdev->dev, "invalid flags 0x%08X vs 0x%08X\n", args->flags, invalid_flags); @@ -579,7 +579,7 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, break; } - if (!r) + if (!r && !(args->flags & AMDGPU_VM_DELAY_UPDATE)) amdgpu_gem_va_update_vm(adev, bo_va); drm_gem_object_unreference_unlocked(gobj); diff --git a/include/uapi/drm/amdgpu_drm.h b/include/uapi/drm/amdgpu_drm.h index 8edf10420361..b6fce900a833 100644 --- a/include/uapi/drm/amdgpu_drm.h +++ b/include/uapi/drm/amdgpu_drm.h @@ -313,6 +313,9 @@ struct drm_amdgpu_gem_op { #define AMDGPU_VA_OP_MAP 1 #define AMDGPU_VA_OP_UNMAP 2 +/* Delay the page table update till the next CS */ +#define AMDGPU_VM_DELAY_UPDATE (1 << 0) + /* Mapping flags */ /* readable mapping */ #define AMDGPU_VM_PAGE_READABLE (1 << 1) -- cgit v1.2.3-70-g09d2 From 11ddba28325a66c2d38dbf987e2d5da790c6d684 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 29 Jun 2015 11:56:27 -0700 Subject: Input: wdt87xx_i2c - fix format warning This fixes the following warning: drivers/input/touchscreen/wdt87xx_i2c.c: In function 'wdt87xx_validate_firmware': >> drivers/input/touchscreen/wdt87xx_i2c.c:472:4: warning: format '%zd' expects argument of type 'signed size_t', but argument 4 has type 'size_t' [-Wformat=] size, fw->size); Reported-by: kbuild test robot Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/wdt87xx_i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/wdt87xx_i2c.c b/drivers/input/touchscreen/wdt87xx_i2c.c index c073ea9345e2..43c3bee4b2e9 100644 --- a/drivers/input/touchscreen/wdt87xx_i2c.c +++ b/drivers/input/touchscreen/wdt87xx_i2c.c @@ -468,7 +468,7 @@ static int wdt87xx_validate_firmware(struct wdt87xx_data *wdt, size = get_unaligned_le32(fw->data + FW_SIZE_OFFSET); if (size != fw->size) { dev_err(&wdt->client->dev, - "fw size mismatch: expected %d, actual %zd\n", + "fw size mismatch: expected %d, actual %zu\n", size, fw->size); return -EINVAL; } -- cgit v1.2.3-70-g09d2 From 580a64bf2b712e43ea04bdded17d7049e7b06ce6 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Mon, 29 Jun 2015 12:13:05 -0700 Subject: Input: arc_ps2 - add HAS_IOMEM dependency Fix this compile error: drivers/built-in.o: In function `arc_ps2_probe': /mnt/linux/drivers/input/serio/arc_ps2.c:206: undefined reference to `devm_ioremap_resource' Signed-off-by: Sebastian Ott Signed-off-by: Dmitry Torokhov --- drivers/input/serio/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig index 77833d7a004b..200841b77edb 100644 --- a/drivers/input/serio/Kconfig +++ b/drivers/input/serio/Kconfig @@ -244,6 +244,7 @@ config SERIO_PS2MULT config SERIO_ARC_PS2 tristate "ARC PS/2 support" + depends on HAS_IOMEM help Say Y here if you have an ARC FPGA platform with a PS/2 controller in it. -- cgit v1.2.3-70-g09d2 From 0a8b83530b6f67b9a50bd7937d57a5deea187b5b Mon Sep 17 00:00:00 2001 From: "qipeng.zha" Date: Sat, 27 Jun 2015 00:32:15 +0800 Subject: intel_pmc_ipc: Add Intel Apollo Lake PMC IPC driver This driver provides support for PMC control on Apollo Lake platforms. The PMC is an ARC processor which defines some IPC commands for communication with other entities in the CPU. Signed-off-by: qipeng.zha [fengguang.wu@intel.com: Fix Sparse and Cocinelle warnings] Signed-off-by: Fengguang Wu Signed-off-by: Darren Hart --- MAINTAINERS | 7 + arch/x86/include/asm/intel_pmc_ipc.h | 82 ++++ drivers/platform/x86/Kconfig | 7 + drivers/platform/x86/Makefile | 1 + drivers/platform/x86/intel_pmc_ipc.c | 767 +++++++++++++++++++++++++++++++++++ 5 files changed, 864 insertions(+) create mode 100644 arch/x86/include/asm/intel_pmc_ipc.h create mode 100644 drivers/platform/x86/intel_pmc_ipc.c (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index 4188e84bd257..3dbdd6d6d3ac 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5264,6 +5264,13 @@ F: include/uapi/linux/mei.h F: drivers/misc/mei/* F: Documentation/misc-devices/mei/* +INTEL PMC IPC DRIVER +M: Zha Qipeng +L: platform-driver-x86@vger.kernel.org +S: Maintained +F: drivers/platform/x86/intel_pmc_ipc.c +F: arch/x86/include/asm/intel_pmc_ipc.h + IOC3 ETHERNET DRIVER M: Ralf Baechle L: linux-mips@linux-mips.org diff --git a/arch/x86/include/asm/intel_pmc_ipc.h b/arch/x86/include/asm/intel_pmc_ipc.h new file mode 100644 index 000000000000..200ec2e7821d --- /dev/null +++ b/arch/x86/include/asm/intel_pmc_ipc.h @@ -0,0 +1,82 @@ +#ifndef _ASM_X86_INTEL_PMC_IPC_H_ +#define _ASM_X86_INTEL_PMC_IPC_H_ + +/* Commands */ +#define PMC_IPC_PMIC_ACCESS 0xFF +#define PMC_IPC_PMIC_ACCESS_READ 0x0 +#define PMC_IPC_PMIC_ACCESS_WRITE 0x1 +#define PMC_IPC_USB_PWR_CTRL 0xF0 +#define PMC_IPC_PMIC_BLACKLIST_SEL 0xEF +#define PMC_IPC_PHY_CONFIG 0xEE +#define PMC_IPC_NORTHPEAK_CTRL 0xED +#define PMC_IPC_PM_DEBUG 0xEC +#define PMC_IPC_PMC_TELEMTRY 0xEB +#define PMC_IPC_PMC_FW_MSG_CTRL 0xEA + +/* IPC return code */ +#define IPC_ERR_NONE 0 +#define IPC_ERR_CMD_NOT_SUPPORTED 1 +#define IPC_ERR_CMD_NOT_SERVICED 2 +#define IPC_ERR_UNABLE_TO_SERVICE 3 +#define IPC_ERR_CMD_INVALID 4 +#define IPC_ERR_CMD_FAILED 5 +#define IPC_ERR_EMSECURITY 6 +#define IPC_ERR_UNSIGNEDKERNEL 7 + +#if IS_ENABLED(CONFIG_INTEL_PMC_IPC) + +/* + * intel_pmc_ipc_simple_command + * @cmd: command + * @sub: sub type + */ +int intel_pmc_ipc_simple_command(int cmd, int sub); + +/* + * intel_pmc_ipc_raw_cmd + * @cmd: command + * @sub: sub type + * @in: input data + * @inlen: input length in bytes + * @out: output data + * @outlen: output length in dwords + * @sptr: data writing to SPTR register + * @dptr: data writing to DPTR register + */ +int intel_pmc_ipc_raw_cmd(u32 cmd, u32 sub, u8 *in, u32 inlen, + u32 *out, u32 outlen, u32 dptr, u32 sptr); + +/* + * intel_pmc_ipc_command + * @cmd: command + * @sub: sub type + * @in: input data + * @inlen: input length in bytes + * @out: output data + * @outlen: output length in dwords + */ +int intel_pmc_ipc_command(u32 cmd, u32 sub, u8 *in, u32 inlen, + u32 *out, u32 outlen); + +#else + +static inline int intel_pmc_ipc_simple_command(int cmd, int sub) +{ + return -EINVAL; +} + +static inline int intel_pmc_ipc_raw_cmd(u32 cmd, u32 sub, u8 *in, u32 inlen, + u32 *out, u32 outlen, u32 dptr, u32 sptr) +{ + return -EINVAL; +} + +static inline int intel_pmc_ipc_command(u32 cmd, u32 sub, u8 *in, u32 inlen, + u32 *out, u32 outlen) +{ + return -EINVAL; +} + +#endif /*CONFIG_INTEL_PMC_IPC*/ + +#endif diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index bca0aee22978..b92f592a4b81 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -901,4 +901,11 @@ config PVPANIC a paravirtualized device provided by QEMU; it lets a virtual machine (guest) communicate panic events to the host. +config INTEL_PMC_IPC + tristate "Intel PMC IPC Driver" + ---help--- + This driver provides support for PMC control on some Intel platforms. + The PMC is an ARC processor which defines IPC commands for communication + with other entities in the CPU. + endif # X86_PLATFORM_DEVICES diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index b3e54ed863c3..dda95a985321 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -59,3 +59,4 @@ obj-$(CONFIG_INTEL_SMARTCONNECT) += intel-smartconnect.o obj-$(CONFIG_PVPANIC) += pvpanic.o obj-$(CONFIG_ALIENWARE_WMI) += alienware-wmi.o +obj-$(CONFIG_INTEL_PMC_IPC) += intel_pmc_ipc.o diff --git a/drivers/platform/x86/intel_pmc_ipc.c b/drivers/platform/x86/intel_pmc_ipc.c new file mode 100644 index 000000000000..d734763dab69 --- /dev/null +++ b/drivers/platform/x86/intel_pmc_ipc.c @@ -0,0 +1,767 @@ +/* + * intel_pmc_ipc.c: Driver for the Intel PMC IPC mechanism + * + * (C) Copyright 2014-2015 Intel Corporation + * + * This driver is based on Intel SCU IPC driver(intel_scu_opc.c) by + * Sreedhara DS + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; version 2 + * of the License. + * + * PMC running in ARC processor communicates with other entity running in IA + * core through IPC mechanism which in turn messaging between IA core ad PMC. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * IPC registers + * The IA write to IPC_CMD command register triggers an interrupt to the ARC, + * The ARC handles the interrupt and services it, writing optional data to + * the IPC1 registers, updates the IPC_STS response register with the status. + */ +#define IPC_CMD 0x0 +#define IPC_CMD_MSI 0x100 +#define IPC_CMD_SIZE 16 +#define IPC_CMD_SUBCMD 12 +#define IPC_STATUS 0x04 +#define IPC_STATUS_IRQ 0x4 +#define IPC_STATUS_ERR 0x2 +#define IPC_STATUS_BUSY 0x1 +#define IPC_SPTR 0x08 +#define IPC_DPTR 0x0C +#define IPC_WRITE_BUFFER 0x80 +#define IPC_READ_BUFFER 0x90 + +/* + * 16-byte buffer for sending data associated with IPC command. + */ +#define IPC_DATA_BUFFER_SIZE 16 + +#define IPC_LOOP_CNT 3000000 +#define IPC_MAX_SEC 3 + +#define IPC_TRIGGER_MODE_IRQ true + +/* exported resources from IFWI */ +#define PLAT_RESOURCE_IPC_INDEX 0 +#define PLAT_RESOURCE_IPC_SIZE 0x1000 +#define PLAT_RESOURCE_GCR_SIZE 0x1000 +#define PLAT_RESOURCE_PUNIT_DATA_INDEX 1 +#define PLAT_RESOURCE_PUNIT_INTER_INDEX 2 +#define PLAT_RESOURCE_ACPI_IO_INDEX 0 + +/* + * BIOS does not create an ACPI device for each PMC function, + * but exports multiple resources from one ACPI device(IPC) for + * multiple functions. This driver is responsible to create a + * platform device and to export resources for those functions. + */ +#define TCO_DEVICE_NAME "iTCO_wdt" +#define SMI_EN_OFFSET 0x30 +#define SMI_EN_SIZE 4 +#define TCO_BASE_OFFSET 0x60 +#define TCO_REGS_SIZE 16 +#define PUNIT_DEVICE_NAME "intel_punit_ipc" + +static const int iTCO_version = 3; + +static struct intel_pmc_ipc_dev { + struct device *dev; + void __iomem *ipc_base; + bool irq_mode; + int irq; + int cmd; + struct completion cmd_complete; + + /* The following PMC BARs share the same ACPI device with the IPC */ + void *acpi_io_base; + int acpi_io_size; + struct platform_device *tco_dev; + + /* gcr */ + void *gcr_base; + int gcr_size; + + /* punit */ + void *punit_base; + int punit_size; + void *punit_base2; + int punit_size2; + struct platform_device *punit_dev; +} ipcdev; + +static char *ipc_err_sources[] = { + [IPC_ERR_NONE] = + "no error", + [IPC_ERR_CMD_NOT_SUPPORTED] = + "command not supported", + [IPC_ERR_CMD_NOT_SERVICED] = + "command not serviced", + [IPC_ERR_UNABLE_TO_SERVICE] = + "unable to service", + [IPC_ERR_CMD_INVALID] = + "command invalid", + [IPC_ERR_CMD_FAILED] = + "command failed", + [IPC_ERR_EMSECURITY] = + "Invalid Battery", + [IPC_ERR_UNSIGNEDKERNEL] = + "Unsigned kernel", +}; + +/* Prevent concurrent calls to the PMC */ +static DEFINE_MUTEX(ipclock); + +static inline void ipc_send_command(u32 cmd) +{ + ipcdev.cmd = cmd; + if (ipcdev.irq_mode) { + reinit_completion(&ipcdev.cmd_complete); + cmd |= IPC_CMD_MSI; + } + writel(cmd, ipcdev.ipc_base + IPC_CMD); +} + +static inline u32 ipc_read_status(void) +{ + return readl(ipcdev.ipc_base + IPC_STATUS); +} + +static inline void ipc_data_writel(u32 data, u32 offset) +{ + writel(data, ipcdev.ipc_base + IPC_WRITE_BUFFER + offset); +} + +static inline u8 ipc_data_readb(u32 offset) +{ + return readb(ipcdev.ipc_base + IPC_READ_BUFFER + offset); +} + +static inline u32 ipc_data_readl(u32 offset) +{ + return readl(ipcdev.ipc_base + IPC_READ_BUFFER + offset); +} + +static int intel_pmc_ipc_check_status(void) +{ + int status; + int ret = 0; + + if (ipcdev.irq_mode) { + if (0 == wait_for_completion_timeout( + &ipcdev.cmd_complete, IPC_MAX_SEC * HZ)) + ret = -ETIMEDOUT; + } else { + int loop_count = IPC_LOOP_CNT; + + while ((ipc_read_status() & IPC_STATUS_BUSY) && --loop_count) + udelay(1); + if (loop_count == 0) + ret = -ETIMEDOUT; + } + + status = ipc_read_status(); + if (ret == -ETIMEDOUT) { + dev_err(ipcdev.dev, + "IPC timed out, TS=0x%x, CMD=0x%x\n", + status, ipcdev.cmd); + return ret; + } + + if (status & IPC_STATUS_ERR) { + int i; + + ret = -EIO; + i = (status >> IPC_CMD_SIZE) & 0xFF; + if (i < ARRAY_SIZE(ipc_err_sources)) + dev_err(ipcdev.dev, + "IPC failed: %s, STS=0x%x, CMD=0x%x\n", + ipc_err_sources[i], status, ipcdev.cmd); + else + dev_err(ipcdev.dev, + "IPC failed: unknown, STS=0x%x, CMD=0x%x\n", + status, ipcdev.cmd); + if ((i == IPC_ERR_UNSIGNEDKERNEL) || (i == IPC_ERR_EMSECURITY)) + ret = -EACCES; + } + + return ret; +} + +/* + * intel_pmc_ipc_simple_command + * @cmd: command + * @sub: sub type + */ +int intel_pmc_ipc_simple_command(int cmd, int sub) +{ + int ret; + + mutex_lock(&ipclock); + if (ipcdev.dev == NULL) { + mutex_unlock(&ipclock); + return -ENODEV; + } + ipc_send_command(sub << IPC_CMD_SUBCMD | cmd); + ret = intel_pmc_ipc_check_status(); + mutex_unlock(&ipclock); + + return ret; +} +EXPORT_SYMBOL_GPL(intel_pmc_ipc_simple_command); + +/* + * intel_pmc_ipc_raw_cmd + * @cmd: command + * @sub: sub type + * @in: input data + * @inlen: input length in bytes + * @out: output data + * @outlen: output length in dwords + * @sptr: data writing to SPTR register + * @dptr: data writing to DPTR register + */ +int intel_pmc_ipc_raw_cmd(u32 cmd, u32 sub, u8 *in, u32 inlen, u32 *out, + u32 outlen, u32 dptr, u32 sptr) +{ + u32 wbuf[4] = { 0 }; + int ret; + int i; + + if (inlen > IPC_DATA_BUFFER_SIZE || outlen > IPC_DATA_BUFFER_SIZE / 4) + return -EINVAL; + + mutex_lock(&ipclock); + if (ipcdev.dev == NULL) { + mutex_unlock(&ipclock); + return -ENODEV; + } + memcpy(wbuf, in, inlen); + writel(dptr, ipcdev.ipc_base + IPC_DPTR); + writel(sptr, ipcdev.ipc_base + IPC_SPTR); + /* The input data register is 32bit register and inlen is in Byte */ + for (i = 0; i < ((inlen + 3) / 4); i++) + ipc_data_writel(wbuf[i], 4 * i); + ipc_send_command((inlen << IPC_CMD_SIZE) | + (sub << IPC_CMD_SUBCMD) | cmd); + ret = intel_pmc_ipc_check_status(); + if (!ret) { + /* out is read from 32bit register and outlen is in 32bit */ + for (i = 0; i < outlen; i++) + *out++ = ipc_data_readl(4 * i); + } + mutex_unlock(&ipclock); + + return ret; +} +EXPORT_SYMBOL_GPL(intel_pmc_ipc_raw_cmd); + +/* + * intel_pmc_ipc_command + * @cmd: command + * @sub: sub type + * @in: input data + * @inlen: input length in bytes + * @out: output data + * @outlen: output length in dwords + */ +int intel_pmc_ipc_command(u32 cmd, u32 sub, u8 *in, u32 inlen, + u32 *out, u32 outlen) +{ + return intel_pmc_ipc_raw_cmd(cmd, sub, in, inlen, out, outlen, 0, 0); +} +EXPORT_SYMBOL_GPL(intel_pmc_ipc_command); + +static irqreturn_t ioc(int irq, void *dev_id) +{ + int status; + + if (ipcdev.irq_mode) { + status = ipc_read_status(); + writel(status | IPC_STATUS_IRQ, ipcdev.ipc_base + IPC_STATUS); + } + complete(&ipcdev.cmd_complete); + + return IRQ_HANDLED; +} + +static int ipc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + resource_size_t pci_resource; + int ret; + int len; + + ipcdev.dev = &pci_dev_get(pdev)->dev; + ipcdev.irq_mode = IPC_TRIGGER_MODE_IRQ; + + ret = pci_enable_device(pdev); + if (ret) + return ret; + + ret = pci_request_regions(pdev, "intel_pmc_ipc"); + if (ret) + return ret; + + pci_resource = pci_resource_start(pdev, 0); + len = pci_resource_len(pdev, 0); + if (!pci_resource || !len) { + dev_err(&pdev->dev, "Failed to get resource\n"); + return -ENOMEM; + } + + init_completion(&ipcdev.cmd_complete); + + if (request_irq(pdev->irq, ioc, 0, "intel_pmc_ipc", &ipcdev)) { + dev_err(&pdev->dev, "Failed to request irq\n"); + return -EBUSY; + } + + ipcdev.ipc_base = ioremap_nocache(pci_resource, len); + if (!ipcdev.ipc_base) { + dev_err(&pdev->dev, "Failed to ioremap ipc base\n"); + free_irq(pdev->irq, &ipcdev); + ret = -ENOMEM; + } + + return ret; +} + +static void ipc_pci_remove(struct pci_dev *pdev) +{ + free_irq(pdev->irq, &ipcdev); + pci_release_regions(pdev); + pci_dev_put(pdev); + iounmap(ipcdev.ipc_base); + ipcdev.dev = NULL; +} + +static const struct pci_device_id ipc_pci_ids[] = { + {PCI_VDEVICE(INTEL, 0x0a94), 0}, + {PCI_VDEVICE(INTEL, 0x1a94), 0}, + { 0,} +}; +MODULE_DEVICE_TABLE(pci, ipc_pci_ids); + +static struct pci_driver ipc_pci_driver = { + .name = "intel_pmc_ipc", + .id_table = ipc_pci_ids, + .probe = ipc_pci_probe, + .remove = ipc_pci_remove, +}; + +static ssize_t intel_pmc_ipc_simple_cmd_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int subcmd; + int cmd; + int ret; + + ret = sscanf(buf, "%d %d", &cmd, &subcmd); + if (ret != 2) { + dev_err(dev, "Error args\n"); + return -EINVAL; + } + + ret = intel_pmc_ipc_simple_command(cmd, subcmd); + if (ret) { + dev_err(dev, "command %d error with %d\n", cmd, ret); + return ret; + } + return (ssize_t)count; +} + +static ssize_t intel_pmc_ipc_northpeak_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long val; + int subcmd; + int ret; + + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + if (val) + subcmd = 1; + else + subcmd = 0; + ret = intel_pmc_ipc_simple_command(PMC_IPC_NORTHPEAK_CTRL, subcmd); + if (ret) { + dev_err(dev, "command north %d error with %d\n", subcmd, ret); + return ret; + } + return (ssize_t)count; +} + +static DEVICE_ATTR(simplecmd, S_IWUSR, + NULL, intel_pmc_ipc_simple_cmd_store); +static DEVICE_ATTR(northpeak, S_IWUSR, + NULL, intel_pmc_ipc_northpeak_store); + +static struct attribute *intel_ipc_attrs[] = { + &dev_attr_northpeak.attr, + &dev_attr_simplecmd.attr, + NULL +}; + +static const struct attribute_group intel_ipc_group = { + .attrs = intel_ipc_attrs, +}; + +#define PUNIT_RESOURCE_INTER 1 +static struct resource punit_res[] = { + /* Punit */ + { + .flags = IORESOURCE_MEM, + }, + { + .flags = IORESOURCE_MEM, + }, +}; + +#define TCO_RESOURCE_ACPI_IO 0 +#define TCO_RESOURCE_SMI_EN_IO 1 +#define TCO_RESOURCE_GCR_MEM 2 +static struct resource tco_res[] = { + /* ACPI - TCO */ + { + .flags = IORESOURCE_IO, + }, + /* ACPI - SMI */ + { + .flags = IORESOURCE_IO, + }, + /* GCS */ + { + .flags = IORESOURCE_MEM, + }, +}; + +static struct lpc_ich_info tco_info = { + .name = "Apollo Lake SoC", + .iTCO_version = 3, +}; + +static int ipc_create_punit_device(void) +{ + struct platform_device *pdev; + struct resource *res; + int ret; + + pdev = platform_device_alloc(PUNIT_DEVICE_NAME, -1); + if (!pdev) { + dev_err(ipcdev.dev, "Failed to alloc punit platform device\n"); + return -ENOMEM; + } + + pdev->dev.parent = ipcdev.dev; + + res = punit_res; + res->start = (resource_size_t)ipcdev.punit_base; + res->end = res->start + ipcdev.punit_size - 1; + + res = punit_res + PUNIT_RESOURCE_INTER; + res->start = (resource_size_t)ipcdev.punit_base2; + res->end = res->start + ipcdev.punit_size2 - 1; + + ret = platform_device_add_resources(pdev, punit_res, + ARRAY_SIZE(punit_res)); + if (ret) { + dev_err(ipcdev.dev, "Failed to add platform punit resources\n"); + goto err; + } + + ret = platform_device_add(pdev); + if (ret) { + dev_err(ipcdev.dev, "Failed to add punit platform device\n"); + goto err; + } + ipcdev.punit_dev = pdev; + + return 0; +err: + platform_device_put(pdev); + return ret; +} + +static int ipc_create_tco_device(void) +{ + struct platform_device *pdev; + struct resource *res; + int ret; + + pdev = platform_device_alloc(TCO_DEVICE_NAME, -1); + if (!pdev) { + dev_err(ipcdev.dev, "Failed to alloc tco platform device\n"); + return -ENOMEM; + } + + pdev->dev.parent = ipcdev.dev; + + res = tco_res + TCO_RESOURCE_ACPI_IO; + res->start = (resource_size_t)ipcdev.acpi_io_base + TCO_BASE_OFFSET; + res->end = res->start + TCO_REGS_SIZE - 1; + + res = tco_res + TCO_RESOURCE_SMI_EN_IO; + res->start = (resource_size_t)ipcdev.acpi_io_base + SMI_EN_OFFSET; + res->end = res->start + SMI_EN_SIZE - 1; + + res = tco_res + TCO_RESOURCE_GCR_MEM; + res->start = (resource_size_t)ipcdev.gcr_base; + res->end = res->start + ipcdev.gcr_size - 1; + + ret = platform_device_add_resources(pdev, tco_res, ARRAY_SIZE(tco_res)); + if (ret) { + dev_err(ipcdev.dev, "Failed to add tco platform resources\n"); + goto err; + } + + ret = platform_device_add_data(pdev, &tco_info, + sizeof(struct lpc_ich_info)); + if (ret) { + dev_err(ipcdev.dev, "Failed to add tco platform data\n"); + goto err; + } + + ret = platform_device_add(pdev); + if (ret) { + dev_err(ipcdev.dev, "Failed to add tco platform device\n"); + goto err; + } + ipcdev.tco_dev = pdev; + + return 0; +err: + platform_device_put(pdev); + return ret; +} + +static int ipc_create_pmc_devices(void) +{ + int ret; + + ret = ipc_create_tco_device(); + if (ret) { + dev_err(ipcdev.dev, "Failed to add tco platform device\n"); + return ret; + } + ret = ipc_create_punit_device(); + if (ret) { + dev_err(ipcdev.dev, "Failed to add punit platform device\n"); + platform_device_unregister(ipcdev.tco_dev); + } + return ret; +} + +static int ipc_plat_get_res(struct platform_device *pdev) +{ + struct resource *res; + void __iomem *addr; + int size; + + res = platform_get_resource(pdev, IORESOURCE_IO, + PLAT_RESOURCE_ACPI_IO_INDEX); + if (!res) { + dev_err(&pdev->dev, "Failed to get io resource\n"); + return -ENXIO; + } + size = resource_size(res); + ipcdev.acpi_io_base = (void *)res->start; + ipcdev.acpi_io_size = size; + dev_info(&pdev->dev, "io res: %llx %x\n", + (long long)res->start, (int)resource_size(res)); + + res = platform_get_resource(pdev, IORESOURCE_MEM, + PLAT_RESOURCE_PUNIT_DATA_INDEX); + if (!res) { + dev_err(&pdev->dev, "Failed to get punit resource\n"); + return -ENXIO; + } + size = resource_size(res); + ipcdev.punit_base = (void *)res->start; + ipcdev.punit_size = size; + dev_info(&pdev->dev, "punit data res: %llx %x\n", + (long long)res->start, (int)resource_size(res)); + + res = platform_get_resource(pdev, IORESOURCE_MEM, + PLAT_RESOURCE_PUNIT_INTER_INDEX); + if (!res) { + dev_err(&pdev->dev, "Failed to get punit inter resource\n"); + return -ENXIO; + } + size = resource_size(res); + ipcdev.punit_base2 = (void *)res->start; + ipcdev.punit_size2 = size; + dev_info(&pdev->dev, "punit interface res: %llx %x\n", + (long long)res->start, (int)resource_size(res)); + + res = platform_get_resource(pdev, IORESOURCE_MEM, + PLAT_RESOURCE_IPC_INDEX); + if (!res) { + dev_err(&pdev->dev, "Failed to get ipc resource\n"); + return -ENXIO; + } + size = PLAT_RESOURCE_IPC_SIZE; + if (!request_mem_region(res->start, size, pdev->name)) { + dev_err(&pdev->dev, "Failed to request ipc resource\n"); + return -EBUSY; + } + addr = ioremap_nocache(res->start, size); + if (!addr) { + dev_err(&pdev->dev, "I/O memory remapping failed\n"); + release_mem_region(res->start, size); + return -ENOMEM; + } + ipcdev.ipc_base = addr; + + ipcdev.gcr_base = (void *)(res->start + size); + ipcdev.gcr_size = PLAT_RESOURCE_GCR_SIZE; + dev_info(&pdev->dev, "ipc res: %llx %x\n", + (long long)res->start, (int)resource_size(res)); + + return 0; +} + +#ifdef CONFIG_ACPI +static const struct acpi_device_id ipc_acpi_ids[] = { + { "INT34D2", 0}, + { } +}; +MODULE_DEVICE_TABLE(acpi, ipc_acpi_ids); +#endif + +static int ipc_plat_probe(struct platform_device *pdev) +{ + struct resource *res; + int ret; + + ipcdev.dev = &pdev->dev; + ipcdev.irq_mode = IPC_TRIGGER_MODE_IRQ; + init_completion(&ipcdev.cmd_complete); + + ipcdev.irq = platform_get_irq(pdev, 0); + if (ipcdev.irq < 0) { + dev_err(&pdev->dev, "Failed to get irq\n"); + return -EINVAL; + } + + ret = ipc_plat_get_res(pdev); + if (ret) { + dev_err(&pdev->dev, "Failed to request resource\n"); + return ret; + } + + ret = ipc_create_pmc_devices(); + if (ret) { + dev_err(&pdev->dev, "Failed to create pmc devices\n"); + goto err_device; + } + + if (request_irq(ipcdev.irq, ioc, 0, "intel_pmc_ipc", &ipcdev)) { + dev_err(&pdev->dev, "Failed to request irq\n"); + ret = -EBUSY; + goto err_irq; + } + + ret = sysfs_create_group(&pdev->dev.kobj, &intel_ipc_group); + if (ret) { + dev_err(&pdev->dev, "Failed to create sysfs group %d\n", + ret); + goto err_sys; + } + + return 0; +err_sys: + free_irq(ipcdev.irq, &ipcdev); +err_irq: + platform_device_unregister(ipcdev.tco_dev); + platform_device_unregister(ipcdev.punit_dev); +err_device: + iounmap(ipcdev.ipc_base); + res = platform_get_resource(pdev, IORESOURCE_MEM, + PLAT_RESOURCE_IPC_INDEX); + if (res) + release_mem_region(res->start, PLAT_RESOURCE_IPC_SIZE); + return ret; +} + +static int ipc_plat_remove(struct platform_device *pdev) +{ + struct resource *res; + + sysfs_remove_group(&pdev->dev.kobj, &intel_ipc_group); + free_irq(ipcdev.irq, &ipcdev); + platform_device_unregister(ipcdev.tco_dev); + platform_device_unregister(ipcdev.punit_dev); + iounmap(ipcdev.ipc_base); + res = platform_get_resource(pdev, IORESOURCE_MEM, + PLAT_RESOURCE_IPC_INDEX); + if (res) + release_mem_region(res->start, PLAT_RESOURCE_IPC_SIZE); + ipcdev.dev = NULL; + return 0; +} + +static struct platform_driver ipc_plat_driver = { + .remove = ipc_plat_remove, + .probe = ipc_plat_probe, + .driver = { + .name = "pmc-ipc-plat", + .acpi_match_table = ACPI_PTR(ipc_acpi_ids), + }, +}; + +static int __init intel_pmc_ipc_init(void) +{ + int ret; + + ret = platform_driver_register(&ipc_plat_driver); + if (ret) { + pr_err("Failed to register PMC ipc platform driver\n"); + return ret; + } + ret = pci_register_driver(&ipc_pci_driver); + if (ret) { + pr_err("Failed to register PMC ipc pci driver\n"); + platform_driver_unregister(&ipc_plat_driver); + return ret; + } + return ret; +} + +static void __exit intel_pmc_ipc_exit(void) +{ + pci_unregister_driver(&ipc_pci_driver); + platform_driver_unregister(&ipc_plat_driver); +} + +MODULE_AUTHOR("Zha Qipeng "); +MODULE_DESCRIPTION("Intel PMC IPC driver"); +MODULE_LICENSE("GPL"); + +/* Some modules are dependent on this, so init earlier */ +fs_initcall(intel_pmc_ipc_init); +module_exit(intel_pmc_ipc_exit); -- cgit v1.2.3-70-g09d2 From 479e9a95120aaae0bf0d3e0b5b26b36ac4a347b6 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 30 Jun 2015 09:30:01 -0400 Subject: drm/radeon: only check the sink type on DP connectors Avoids a crash on pre-DP asics that support HDMI. Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/radeon_audio.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_audio.c b/drivers/gpu/drm/radeon/radeon_audio.c index c89215275053..fa719c53449b 100644 --- a/drivers/gpu/drm/radeon/radeon_audio.c +++ b/drivers/gpu/drm/radeon/radeon_audio.c @@ -469,22 +469,22 @@ void radeon_audio_detect(struct drm_connector *connector, dig = radeon_encoder->enc_priv; if (status == connector_status_connected) { - struct radeon_connector *radeon_connector; - int sink_type; - if (!drm_detect_monitor_audio(radeon_connector_edid(connector))) { radeon_encoder->audio = NULL; return; } - radeon_connector = to_radeon_connector(connector); - sink_type = radeon_dp_getsinktype(radeon_connector); + if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) { + struct radeon_connector *radeon_connector = to_radeon_connector(connector); - if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort && - sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) - radeon_encoder->audio = rdev->audio.dp_funcs; - else + if (radeon_dp_getsinktype(radeon_connector) == + CONNECTOR_OBJECT_ID_DISPLAYPORT) + radeon_encoder->audio = rdev->audio.dp_funcs; + else + radeon_encoder->audio = rdev->audio.hdmi_funcs; + } else { radeon_encoder->audio = rdev->audio.hdmi_funcs; + } dig->afmt->pin = radeon_audio_get_pin(connector->encoder); radeon_audio_enable(rdev, dig->afmt->pin, 0xf); -- cgit v1.2.3-70-g09d2 From ee46f3c7d79c334e8bdc9947503e329dc27c0b47 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Tue, 30 Jun 2015 16:10:38 +0300 Subject: drm/i915: Clear pipe's pll hw state in hsw_dp_set_ddi_pll_sel() Similarly to what is done for SKL, clear the dpll_hw_state of the pipe config in hsw_dp_set_ddi_pll_sel(), since it main contain stale values. That can happen if a crtc that was previously driving an HDMI connector switches to a DP connector. In that case, the wrpll field was left with its old value, leading to warnings like the one below: [drm:check_crtc_state [i915]] *ERROR* mismatch in dpll_hw_state.wrpll (expected 0xb035061f, found 0x00000000) ------------[ cut here ]------------ WARNING: CPU: 1 PID: 767 at drivers/gpu/drm/i915/intel_display.c:12324 check_crtc_state+0x975/0x10b0 [i915]() pipe state doesn't match! This regression was indroduced in commit dd3cd74acf12723045a64f1f2c6298ac7b34a5d5 Author: Ander Conselvan de Oliveira Date: Fri May 15 13:34:29 2015 +0300 drm/i915: Don't overwrite (e)DP PLL selection on SKL Reported-by: Linus Torvalds Signed-off-by: Ander Conselvan de Oliveira Tested-by: Jani Nikula Reviewed-by: Daniel Vetter Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_dp.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 280c282da9bd..16c86ce942ea 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1141,6 +1141,9 @@ skl_edp_set_pll_config(struct intel_crtc_state *pipe_config, int link_clock) static void hsw_dp_set_ddi_pll_sel(struct intel_crtc_state *pipe_config, int link_bw) { + memset(&pipe_config->dpll_hw_state, 0, + sizeof(pipe_config->dpll_hw_state)); + switch (link_bw) { case DP_LINK_BW_1_62: pipe_config->ddi_pll_sel = PORT_CLK_SEL_LCPLL_810; -- cgit v1.2.3-70-g09d2 From af834d457d9ed69e14836b63d0da198fdd2ec706 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 30 Jun 2015 14:10:09 -0400 Subject: libnvdimm: smatch cleanups in __nd_ioctl Drop use of access_ok() since we are already using copy_{to|from}_user() which do their own access_ok(). Reported-by: Dan Carpenter Signed-off-by: Dan Williams --- drivers/nvdimm/bus.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c index 8eb22c0ca7ce..73442bd824a7 100644 --- a/drivers/nvdimm/bus.c +++ b/drivers/nvdimm/bus.c @@ -535,8 +535,6 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm, __func__, dimm_name, cmd_name, i); return -ENXIO; } - if (!access_ok(VERIFY_READ, p + in_len, in_size)) - return -EFAULT; if (in_len < sizeof(in_env)) copy = min_t(u32, sizeof(in_env) - in_len, in_size); else @@ -557,8 +555,6 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm, __func__, dimm_name, cmd_name, i); return -EFAULT; } - if (!access_ok(VERIFY_WRITE, p + in_len + out_len, out_size)) - return -EFAULT; if (out_len < sizeof(out_env)) copy = min_t(u32, sizeof(out_env) - out_len, out_size); else @@ -570,9 +566,6 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm, } buf_len = out_len + in_len; - if (!access_ok(VERIFY_WRITE, p, sizeof(buf_len))) - return -EFAULT; - if (buf_len > ND_IOCTL_MAX_BUFLEN) { dev_dbg(dev, "%s:%s cmd: %s buf_len: %zu > %d\n", __func__, dimm_name, cmd_name, buf_len, -- cgit v1.2.3-70-g09d2 From daa1dee405d7d3d3e816b84a692e838a5647a02a Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 28 Jun 2015 17:00:57 +0800 Subject: nvdimm: Fix return value of nvdimm_bus_init() if class_create() fails Return proper error if class_create() fails. Signed-off-by: Axel Lin Signed-off-by: Dan Williams --- drivers/nvdimm/bus.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c index 73442bd824a7..7e2c43f701bc 100644 --- a/drivers/nvdimm/bus.c +++ b/drivers/nvdimm/bus.c @@ -699,8 +699,10 @@ int __init nvdimm_bus_init(void) nvdimm_major = rc; nd_class = class_create(THIS_MODULE, "nd"); - if (IS_ERR(nd_class)) + if (IS_ERR(nd_class)) { + rc = PTR_ERR(nd_class); goto err_class; + } return 0; -- cgit v1.2.3-70-g09d2 From 193ccca43850d2355e7690a93ab9d7d78d38f905 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 30 Jun 2015 16:09:39 -0400 Subject: nfit: fix smatch "use after null check" report drivers/acpi/nfit.c:1224 acpi_nfit_blk_region_enable() error: we previously assumed 'nfit_mem' could be null (see line 1223) drivers/acpi/nfit.c 1222 nfit_mem = nvdimm_provider_data(nvdimm); 1223 if (!nfit_mem || !nfit_mem->dcr || !nfit_mem->bdw) { ^^^^^^^^ Check. 1224 dev_dbg(dev, "%s: missing%s%s%s\n", __func__, 1225 nfit_mem ? "" : " nfit_mem", 1226 nfit_mem->dcr ? "" : " dcr", ^^^^^^^^^^^^^ Unchecked dereference. Reported-by: Dan Carpenter Acked-by: Ross Zwisler Signed-off-by: Dan Williams --- drivers/acpi/nfit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/nfit.c b/drivers/acpi/nfit.c index 2161fa178c8d..a20b7c883ca0 100644 --- a/drivers/acpi/nfit.c +++ b/drivers/acpi/nfit.c @@ -1223,8 +1223,8 @@ static int acpi_nfit_blk_region_enable(struct nvdimm_bus *nvdimm_bus, if (!nfit_mem || !nfit_mem->dcr || !nfit_mem->bdw) { dev_dbg(dev, "%s: missing%s%s%s\n", __func__, nfit_mem ? "" : " nfit_mem", - nfit_mem->dcr ? "" : " dcr", - nfit_mem->bdw ? "" : " bdw"); + (nfit_mem && nfit_mem->dcr) ? "" : " dcr", + (nfit_mem && nfit_mem->bdw) ? "" : " bdw"); return -ENXIO; } -- cgit v1.2.3-70-g09d2 From 5a60e87603c4c533492c515b7f62578189b03c9c Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Wed, 24 Jun 2015 17:24:33 +0300 Subject: rbd: use GFP_NOIO in rbd_obj_request_create() rbd_obj_request_create() is called on the main I/O path, so we need to use GFP_NOIO to make sure allocation doesn't blow back on us. Not all callers need this, but I'm still hardcoding the flag inside rather than making it a parameter because a) this is going to stable, and b) those callers shouldn't really use rbd_obj_request_create() and will be fixed in the future. More memory allocation fixes will follow. Cc: stable@vger.kernel.org # 3.10+ Signed-off-by: Ilya Dryomov Reviewed-by: Alex Elder --- drivers/block/rbd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index b316ee48a30b..d94529d5c8e9 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -2022,11 +2022,11 @@ static struct rbd_obj_request *rbd_obj_request_create(const char *object_name, rbd_assert(obj_request_type_valid(type)); size = strlen(object_name) + 1; - name = kmalloc(size, GFP_KERNEL); + name = kmalloc(size, GFP_NOIO); if (!name) return NULL; - obj_request = kmem_cache_zalloc(rbd_obj_request_cache, GFP_KERNEL); + obj_request = kmem_cache_zalloc(rbd_obj_request_cache, GFP_NOIO); if (!obj_request) { kfree(name); return NULL; -- cgit v1.2.3-70-g09d2 From bd5717a4632cdecafe82d03de7dcb3b1876e2828 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Fri, 26 Jun 2015 14:47:21 -0700 Subject: hwspinlock: qcom: Correct msb in regmap_field msb of the regmap_field was mistakenly given the value 32, to set all bits in the regmap update mask; although incorrect this worked until 921cc294, where the mask calculation was corrected. Signed-off-by: Bjorn Andersson Signed-off-by: Ohad Ben-Cohen --- drivers/hwspinlock/qcom_hwspinlock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hwspinlock/qcom_hwspinlock.c b/drivers/hwspinlock/qcom_hwspinlock.c index 93b62e055ff6..c752447fbac7 100644 --- a/drivers/hwspinlock/qcom_hwspinlock.c +++ b/drivers/hwspinlock/qcom_hwspinlock.c @@ -123,7 +123,7 @@ static int qcom_hwspinlock_probe(struct platform_device *pdev) for (i = 0; i < QCOM_MUTEX_NUM_LOCKS; i++) { field.reg = base + i * stride; field.lsb = 0; - field.msb = 32; + field.msb = 31; bank->lock[i].priv = devm_regmap_field_alloc(&pdev->dev, regmap, field); -- cgit v1.2.3-70-g09d2 From f9bb48825a6b5d02f4cabcc78967c75db903dcdc Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 13 May 2015 17:35:41 -0500 Subject: sysfs: Create mountpoints with sysfs_create_mount_point This allows for better documentation in the code and it allows for a simpler and fully correct version of fs_fully_visible to be written. The mount points converted and their filesystems are: /sys/hypervisor/s390/ s390_hypfs /sys/kernel/config/ configfs /sys/kernel/debug/ debugfs /sys/firmware/efi/efivars/ efivarfs /sys/fs/fuse/connections/ fusectl /sys/fs/pstore/ pstore /sys/kernel/tracing/ tracefs /sys/fs/cgroup/ cgroup /sys/kernel/security/ securityfs /sys/fs/selinux/ selinuxfs /sys/fs/smackfs/ smackfs Cc: stable@vger.kernel.org Acked-by: Greg Kroah-Hartman Signed-off-by: "Eric W. Biederman" --- arch/s390/hypfs/inode.c | 12 ++++-------- drivers/firmware/efi/efi.c | 6 ++---- fs/configfs/mount.c | 10 ++++------ fs/debugfs/inode.c | 11 ++++------- fs/fuse/inode.c | 9 +++------ fs/pstore/inode.c | 12 ++++-------- fs/tracefs/inode.c | 6 ++---- kernel/cgroup.c | 10 ++++------ security/inode.c | 10 ++++------ security/selinux/selinuxfs.c | 11 +++++------ security/smack/smackfs.c | 8 ++++---- 11 files changed, 40 insertions(+), 65 deletions(-) (limited to 'drivers') diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c index d3f896a35b98..2eeb0a0f506d 100644 --- a/arch/s390/hypfs/inode.c +++ b/arch/s390/hypfs/inode.c @@ -456,8 +456,6 @@ static const struct super_operations hypfs_s_ops = { .show_options = hypfs_show_options, }; -static struct kobject *s390_kobj; - static int __init hypfs_init(void) { int rc; @@ -481,18 +479,16 @@ static int __init hypfs_init(void) rc = -ENODATA; goto fail_hypfs_sprp_exit; } - s390_kobj = kobject_create_and_add("s390", hypervisor_kobj); - if (!s390_kobj) { - rc = -ENOMEM; + rc = sysfs_create_mount_point(hypervisor_kobj, "s390"); + if (rc) goto fail_hypfs_diag0c_exit; - } rc = register_filesystem(&hypfs_type); if (rc) goto fail_filesystem; return 0; fail_filesystem: - kobject_put(s390_kobj); + sysfs_remove_mount_point(hypervisor_kobj, "s390"); fail_hypfs_diag0c_exit: hypfs_diag0c_exit(); fail_hypfs_sprp_exit: @@ -510,7 +506,7 @@ fail_dbfs_exit: static void __exit hypfs_exit(void) { unregister_filesystem(&hypfs_type); - kobject_put(s390_kobj); + sysfs_remove_mount_point(hypervisor_kobj, "s390"); hypfs_diag0c_exit(); hypfs_sprp_exit(); hypfs_vm_exit(); diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 3061bb8629dc..e14363d12690 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -65,7 +65,6 @@ static int __init parse_efi_cmdline(char *str) early_param("efi", parse_efi_cmdline); static struct kobject *efi_kobj; -static struct kobject *efivars_kobj; /* * Let's not leave out systab information that snuck into @@ -212,10 +211,9 @@ static int __init efisubsys_init(void) goto err_remove_group; /* and the standard mountpoint for efivarfs */ - efivars_kobj = kobject_create_and_add("efivars", efi_kobj); - if (!efivars_kobj) { + error = sysfs_create_mount_point(efi_kobj, "efivars"); + if (error) { pr_err("efivars: Subsystem registration failed.\n"); - error = -ENOMEM; goto err_remove_group; } diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c index da94e41bdbf6..bca58da65e2b 100644 --- a/fs/configfs/mount.c +++ b/fs/configfs/mount.c @@ -129,8 +129,6 @@ void configfs_release_fs(void) } -static struct kobject *config_kobj; - static int __init configfs_init(void) { int err = -ENOMEM; @@ -141,8 +139,8 @@ static int __init configfs_init(void) if (!configfs_dir_cachep) goto out; - config_kobj = kobject_create_and_add("config", kernel_kobj); - if (!config_kobj) + err = sysfs_create_mount_point(kernel_kobj, "config"); + if (err) goto out2; err = register_filesystem(&configfs_fs_type); @@ -152,7 +150,7 @@ static int __init configfs_init(void) return 0; out3: pr_err("Unable to register filesystem!\n"); - kobject_put(config_kobj); + sysfs_remove_mount_point(kernel_kobj, "config"); out2: kmem_cache_destroy(configfs_dir_cachep); configfs_dir_cachep = NULL; @@ -163,7 +161,7 @@ out: static void __exit configfs_exit(void) { unregister_filesystem(&configfs_fs_type); - kobject_put(config_kobj); + sysfs_remove_mount_point(kernel_kobj, "config"); kmem_cache_destroy(configfs_dir_cachep); configfs_dir_cachep = NULL; } diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index c1e7ffb0dab6..12756040ca20 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -716,20 +716,17 @@ bool debugfs_initialized(void) } EXPORT_SYMBOL_GPL(debugfs_initialized); - -static struct kobject *debug_kobj; - static int __init debugfs_init(void) { int retval; - debug_kobj = kobject_create_and_add("debug", kernel_kobj); - if (!debug_kobj) - return -EINVAL; + retval = sysfs_create_mount_point(kernel_kobj, "debug"); + if (retval) + return retval; retval = register_filesystem(&debug_fs_type); if (retval) - kobject_put(debug_kobj); + sysfs_remove_mount_point(kernel_kobj, "debug"); else debugfs_registered = true; diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 082ac1c97f39..18dacf9ed8ff 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -1238,7 +1238,6 @@ static void fuse_fs_cleanup(void) } static struct kobject *fuse_kobj; -static struct kobject *connections_kobj; static int fuse_sysfs_init(void) { @@ -1250,11 +1249,9 @@ static int fuse_sysfs_init(void) goto out_err; } - connections_kobj = kobject_create_and_add("connections", fuse_kobj); - if (!connections_kobj) { - err = -ENOMEM; + err = sysfs_create_mount_point(fuse_kobj, "connections"); + if (err) goto out_fuse_unregister; - } return 0; @@ -1266,7 +1263,7 @@ static int fuse_sysfs_init(void) static void fuse_sysfs_cleanup(void) { - kobject_put(connections_kobj); + sysfs_remove_mount_point(fuse_kobj, "connections"); kobject_put(fuse_kobj); } diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c index dc43b5f29305..3adcc4669fac 100644 --- a/fs/pstore/inode.c +++ b/fs/pstore/inode.c @@ -461,22 +461,18 @@ static struct file_system_type pstore_fs_type = { .kill_sb = pstore_kill_sb, }; -static struct kobject *pstore_kobj; - static int __init init_pstore_fs(void) { - int err = 0; + int err; /* Create a convenient mount point for people to access pstore */ - pstore_kobj = kobject_create_and_add("pstore", fs_kobj); - if (!pstore_kobj) { - err = -ENOMEM; + err = sysfs_create_mount_point(fs_kobj, "pstore"); + if (err) goto out; - } err = register_filesystem(&pstore_fs_type); if (err < 0) - kobject_put(pstore_kobj); + sysfs_remove_mount_point(fs_kobj, "pstore"); out: return err; diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c index d92bdf3b079a..a43df11a163f 100644 --- a/fs/tracefs/inode.c +++ b/fs/tracefs/inode.c @@ -631,14 +631,12 @@ bool tracefs_initialized(void) return tracefs_registered; } -static struct kobject *trace_kobj; - static int __init tracefs_init(void) { int retval; - trace_kobj = kobject_create_and_add("tracing", kernel_kobj); - if (!trace_kobj) + retval = sysfs_create_mount_point(kernel_kobj, "tracing"); + if (retval) return -EINVAL; retval = register_filesystem(&trace_fs_type); diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 469dd547770c..e8a5491be756 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -1924,8 +1924,6 @@ static struct file_system_type cgroup_fs_type = { .kill_sb = cgroup_kill_sb, }; -static struct kobject *cgroup_kobj; - /** * task_cgroup_path - cgroup path of a task in the first cgroup hierarchy * @task: target task @@ -5044,13 +5042,13 @@ int __init cgroup_init(void) ss->bind(init_css_set.subsys[ssid]); } - cgroup_kobj = kobject_create_and_add("cgroup", fs_kobj); - if (!cgroup_kobj) - return -ENOMEM; + err = sysfs_create_mount_point(fs_kobj, "cgroup"); + if (err) + return err; err = register_filesystem(&cgroup_fs_type); if (err < 0) { - kobject_put(cgroup_kobj); + sysfs_remove_mount_point(fs_kobj, "cgroup"); return err; } diff --git a/security/inode.c b/security/inode.c index 91503b79c5f8..0e37e4fba8fa 100644 --- a/security/inode.c +++ b/security/inode.c @@ -215,19 +215,17 @@ void securityfs_remove(struct dentry *dentry) } EXPORT_SYMBOL_GPL(securityfs_remove); -static struct kobject *security_kobj; - static int __init securityfs_init(void) { int retval; - security_kobj = kobject_create_and_add("security", kernel_kobj); - if (!security_kobj) - return -EINVAL; + retval = sysfs_create_mount_point(kernel_kobj, "security"); + if (retval) + return retval; retval = register_filesystem(&fs_type); if (retval) - kobject_put(security_kobj); + sysfs_remove_mount_point(kernel_kobj, "security"); return retval; } diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index d2787cca1fcb..3d2201413028 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -1853,7 +1853,6 @@ static struct file_system_type sel_fs_type = { }; struct vfsmount *selinuxfs_mount; -static struct kobject *selinuxfs_kobj; static int __init init_sel_fs(void) { @@ -1862,13 +1861,13 @@ static int __init init_sel_fs(void) if (!selinux_enabled) return 0; - selinuxfs_kobj = kobject_create_and_add("selinux", fs_kobj); - if (!selinuxfs_kobj) - return -ENOMEM; + err = sysfs_create_mount_point(fs_kobj, "selinux"); + if (err) + return err; err = register_filesystem(&sel_fs_type); if (err) { - kobject_put(selinuxfs_kobj); + sysfs_remove_mount_point(fs_kobj, "selinux"); return err; } @@ -1887,7 +1886,7 @@ __initcall(init_sel_fs); #ifdef CONFIG_SECURITY_SELINUX_DISABLE void exit_sel_fs(void) { - kobject_put(selinuxfs_kobj); + sysfs_remove_mount_point(fs_kobj, "selinux"); kern_unmount(selinuxfs_mount); unregister_filesystem(&sel_fs_type); } diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index d9682985349e..ac4cac7c661a 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c @@ -2241,16 +2241,16 @@ static const struct file_operations smk_revoke_subj_ops = { .llseek = generic_file_llseek, }; -static struct kset *smackfs_kset; /** * smk_init_sysfs - initialize /sys/fs/smackfs * */ static int smk_init_sysfs(void) { - smackfs_kset = kset_create_and_add("smackfs", NULL, fs_kobj); - if (!smackfs_kset) - return -ENOMEM; + int err; + err = sysfs_create_mount_point(fs_kobj, "smackfs"); + if (err) + return err; return 0; } -- cgit v1.2.3-70-g09d2 From 57ff96e0f08bb16c49f66250c9d90452dbbf1293 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 30 Jun 2015 11:28:43 -0700 Subject: Input: wdt87xx_i2c - remove stray newline in diagnostic message There is no reason to have a newline between plat_id and xml_id1. Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/wdt87xx_i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/wdt87xx_i2c.c b/drivers/input/touchscreen/wdt87xx_i2c.c index 43c3bee4b2e9..9eb8e8cec17e 100644 --- a/drivers/input/touchscreen/wdt87xx_i2c.c +++ b/drivers/input/touchscreen/wdt87xx_i2c.c @@ -442,7 +442,7 @@ static int wdt87xx_get_sysparam(struct i2c_client *client, param->fw_id = get_unaligned_le16(&buf[1]); dev_info(&client->dev, - "fw_id: 0x%x, plat_id: 0x%x\nxml_id1: %04x, xml_id2: %04x\n", + "fw_id: 0x%x, plat_id: 0x%x, xml_id1: %04x, xml_id2: %04x\n", param->fw_id, param->plat_id, param->xmls_id1, param->xmls_id2); -- cgit v1.2.3-70-g09d2 From d55d0b56b9c3a0d94ca6cc1643063610c138dde9 Mon Sep 17 00:00:00 2001 From: HungNien Chen Date: Wed, 1 Jul 2015 10:06:49 -0700 Subject: Input: wdt87xx_i2c - add a scaling factor for TOUCH_MAJOR event Get the scaling factor when it reads the sys params. The width value will multiple the factor and report the value in the TOUCH_MAJOR event. Signed-off-by: HungNien Chen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/wdt87xx_i2c.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/wdt87xx_i2c.c b/drivers/input/touchscreen/wdt87xx_i2c.c index 9eb8e8cec17e..fb92ae1c5fae 100644 --- a/drivers/input/touchscreen/wdt87xx_i2c.c +++ b/drivers/input/touchscreen/wdt87xx_i2c.c @@ -23,7 +23,7 @@ #include #define WDT87XX_NAME "wdt87xx_i2c" -#define WDT87XX_DRV_VER "0.9.5" +#define WDT87XX_DRV_VER "0.9.6" #define WDT87XX_FW_NAME "wdt87xx_fw.bin" #define WDT87XX_CFG_NAME "wdt87xx_cfg.bin" @@ -83,6 +83,7 @@ #define CTL_PARAM_OFFSET_PHY_Y1 18 #define CTL_PARAM_OFFSET_PHY_W 22 #define CTL_PARAM_OFFSET_PHY_H 24 +#define CTL_PARAM_OFFSET_FACTOR 32 /* Communication commands */ #define PACKET_SIZE 56 @@ -161,6 +162,7 @@ struct wdt87xx_sys_param { u16 phy_ch_y; u16 phy_w; u16 phy_h; + u16 scaling_factor; u32 max_x; u32 max_y; }; @@ -401,7 +403,7 @@ static int wdt87xx_get_sysparam(struct i2c_client *client, u8 buf[PKT_READ_SIZE]; int error; - error = wdt87xx_get_string(client, STRIDX_PARAMETERS, buf, 32); + error = wdt87xx_get_string(client, STRIDX_PARAMETERS, buf, 34); if (error) { dev_err(&client->dev, "failed to get parameters\n"); return error; @@ -414,6 +416,10 @@ static int wdt87xx_get_sysparam(struct i2c_client *client, param->phy_w = get_unaligned_le16(buf + CTL_PARAM_OFFSET_PHY_W) / 10; param->phy_h = get_unaligned_le16(buf + CTL_PARAM_OFFSET_PHY_H) / 10; + /* Get the scaling factor of pixel to logical coordinate */ + param->scaling_factor = + get_unaligned_le16(buf + CTL_PARAM_OFFSET_FACTOR); + param->max_x = MAX_UNIT_AXIS; param->max_y = DIV_ROUND_CLOSEST(MAX_UNIT_AXIS * param->phy_h, param->phy_w); @@ -905,8 +911,8 @@ static void wdt87xx_report_contact(struct input_dev *input, u8 *buf) { int finger_id; - u32 x, y; - u8 w, p; + u32 x, y, w; + u8 p; finger_id = (buf[FINGER_EV_V1_OFFSET_ID] >> 3) - 1; if (finger_id < 0) @@ -917,6 +923,8 @@ static void wdt87xx_report_contact(struct input_dev *input, return; w = buf[FINGER_EV_V1_OFFSET_W]; + w *= param->scaling_factor; + p = buf[FINGER_EV_V1_OFFSET_P]; x = get_unaligned_le16(buf + FINGER_EV_V1_OFFSET_X); @@ -995,7 +1003,8 @@ static int wdt87xx_ts_create_input_device(struct wdt87xx_data *wdt) input_abs_set_res(input, ABS_MT_POSITION_X, res); input_abs_set_res(input, ABS_MT_POSITION_Y, res); - input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 0xFF, 0, 0); + input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, + 0, wdt->param.max_x, 0, 0); input_set_abs_params(input, ABS_MT_PRESSURE, 0, 0xFF, 0, 0); input_mt_init_slots(input, WDT_MAX_FINGER, -- cgit v1.2.3-70-g09d2 From 498f09bce4dc0a2803df7fc25befbdb249074b85 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 2 Jun 2015 12:12:58 -0700 Subject: soc: qcom: spm: Fix idle on THUMB2 kernels The ifc6410 firmware always enters the kernel in ARM state from deep idle. Use the cpu_resume_arm() wrapper instead of cpu_resume() to property switch into the THUMB2 state when we wake up from idle. This fixes a problem reported by Kevin Hilman on next-20150601 where the ifc6410 fails to boot a THUMB2 kernel because the platform's firmware always enters the kernel in ARM mode from deep idle states. Reported-by: Kevin Hilman Cc: Ard Biesheuvel Cc: Lina Iyer Signed-off-by: Stephen Boyd Signed-off-by: Kevin Hilman --- drivers/soc/qcom/spm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/soc/qcom/spm.c b/drivers/soc/qcom/spm.c index b562af816c0a..b04b05a0904e 100644 --- a/drivers/soc/qcom/spm.c +++ b/drivers/soc/qcom/spm.c @@ -260,7 +260,7 @@ static int __init qcom_cpuidle_init(struct device_node *cpu_node, int cpu) /* We have atleast one power down mode */ cpumask_clear(&mask); cpumask_set_cpu(cpu, &mask); - qcom_scm_set_warm_boot_addr(cpu_resume, &mask); + qcom_scm_set_warm_boot_addr(cpu_resume_arm, &mask); } per_cpu(qcom_idle_ops, cpu) = fns; -- cgit v1.2.3-70-g09d2 From 9026cae1c6d6c288dff0dc1d8350a949432819d8 Mon Sep 17 00:00:00 2001 From: Gabriele Mazzotta Date: Sat, 27 Jun 2015 15:22:05 +0200 Subject: hwmon: (dell-smm-hwmon) Use a valid name attribute MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As per Documentation/hwmon/sysfs-interface, hwmon name attributes must not include '-', so replace 'dell-smm' with 'dell_smm'. Fixes: 039ae58503f3 ("hwmon: Allow to compile dell-smm-hwmon driver without /proc/i8k") Signed-off-by: Gabriele Mazzotta Acked-by: Pali Rohár Signed-off-by: Guenter Roeck --- drivers/hwmon/dell-smm-hwmon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c index 2a808822af21..37c16afe007a 100644 --- a/drivers/hwmon/dell-smm-hwmon.c +++ b/drivers/hwmon/dell-smm-hwmon.c @@ -777,7 +777,7 @@ static int __init i8k_init_hwmon(void) if (err >= 0) i8k_hwmon_flags |= I8K_HWMON_HAVE_FAN2; - i8k_hwmon_dev = hwmon_device_register_with_groups(NULL, "dell-smm", + i8k_hwmon_dev = hwmon_device_register_with_groups(NULL, "dell_smm", NULL, i8k_groups); if (IS_ERR(i8k_hwmon_dev)) { err = PTR_ERR(i8k_hwmon_dev); -- cgit v1.2.3-70-g09d2 From 56172d81a9bc37a69b95dd627b8d48135c9c7b31 Mon Sep 17 00:00:00 2001 From: Constantine Shulyupin Date: Fri, 26 Jun 2015 17:47:44 +0300 Subject: hwmon: (nct7802) fix visibility of temp3 Excerpt from datasheet: 7.2.32 Mode Selection Register RTD3_MD : 00=Closed , 01=Reserved , 10=Thermistor mode , 11=Voltage sense Show temp3 only in Thermistor mode Cc: stable@vger.kernel.org # v3.19+ Signed-off-by: Constantine Shulyupin Signed-off-by: Guenter Roeck --- drivers/hwmon/nct7802.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hwmon/nct7802.c b/drivers/hwmon/nct7802.c index 55765790907b..28fcb2e246d5 100644 --- a/drivers/hwmon/nct7802.c +++ b/drivers/hwmon/nct7802.c @@ -547,7 +547,7 @@ static umode_t nct7802_temp_is_visible(struct kobject *kobj, if (index >= 9 && index < 18 && (reg & 0x0c) != 0x04 && (reg & 0x0c) != 0x08) /* RD2 */ return 0; - if (index >= 18 && index < 27 && (reg & 0x30) != 0x10) /* RD3 */ + if (index >= 18 && index < 27 && (reg & 0x30) != 0x20) /* RD3 */ return 0; if (index >= 27 && index < 35) /* local */ return attr->mode; -- cgit v1.2.3-70-g09d2 From 347d7e45bd09ce09cbc30d5cea9de377eb22f55c Mon Sep 17 00:00:00 2001 From: "Stevens, Nick" Date: Wed, 1 Jul 2015 16:07:41 +0000 Subject: hwmon: (mcp3021) Fix broken output scaling The mcp3021 scaling code is dividing the VDD (full-scale) value in millivolts by the A2D resolution to obtain the scaling factor. When VDD is 3300mV (the standard value) and the resolution is 12-bit (4096 divisions), the result is a scale factor of 3300/4096, which is always one. Effectively, the raw A2D reading is always being returned because no scaling is applied. This patch fixes the issue and simplifies the register-to-volts calculation, removing the unneeded "output_scale" struct member. Signed-off-by: Nick Stevens Cc: stable@vger.kernel.org # v3.10+ [Guenter Roeck: Dropped unnecessary value check] Signed-off-by: Guenter Roeck --- drivers/hwmon/mcp3021.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/mcp3021.c b/drivers/hwmon/mcp3021.c index d219c06a857b..972444a14cca 100644 --- a/drivers/hwmon/mcp3021.c +++ b/drivers/hwmon/mcp3021.c @@ -31,14 +31,11 @@ /* output format */ #define MCP3021_SAR_SHIFT 2 #define MCP3021_SAR_MASK 0x3ff - #define MCP3021_OUTPUT_RES 10 /* 10-bit resolution */ -#define MCP3021_OUTPUT_SCALE 4 #define MCP3221_SAR_SHIFT 0 #define MCP3221_SAR_MASK 0xfff #define MCP3221_OUTPUT_RES 12 /* 12-bit resolution */ -#define MCP3221_OUTPUT_SCALE 1 enum chips { mcp3021, @@ -54,7 +51,6 @@ struct mcp3021_data { u16 sar_shift; u16 sar_mask; u8 output_res; - u8 output_scale; }; static int mcp3021_read16(struct i2c_client *client) @@ -84,13 +80,7 @@ static int mcp3021_read16(struct i2c_client *client) static inline u16 volts_from_reg(struct mcp3021_data *data, u16 val) { - if (val == 0) - return 0; - - val = val * data->output_scale - data->output_scale / 2; - - return val * DIV_ROUND_CLOSEST(data->vdd, - (1 << data->output_res) * data->output_scale); + return DIV_ROUND_CLOSEST(data->vdd * val, 1 << data->output_res); } static ssize_t show_in_input(struct device *dev, struct device_attribute *attr, @@ -132,14 +122,12 @@ static int mcp3021_probe(struct i2c_client *client, data->sar_shift = MCP3021_SAR_SHIFT; data->sar_mask = MCP3021_SAR_MASK; data->output_res = MCP3021_OUTPUT_RES; - data->output_scale = MCP3021_OUTPUT_SCALE; break; case mcp3221: data->sar_shift = MCP3221_SAR_SHIFT; data->sar_mask = MCP3221_SAR_MASK; data->output_res = MCP3221_OUTPUT_RES; - data->output_scale = MCP3221_OUTPUT_SCALE; break; } -- cgit v1.2.3-70-g09d2 From aca2a5d3a8fce1879627bc4ec9d180b74ae512e2 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 1 Jul 2015 14:43:04 +0800 Subject: ACPICA: Hardware: Enable 64-bit firmware waking vector for selected FACS ACPICA commit 7aa598d711644ab0de5f70ad88f1e2de253115e4 The following commit is reported to have broken s2ram on some platforms: Commit: 0249ed2444d65d65fc3f3f64f398f1ad0b7e54cd ACPICA: Add option to favor 32-bit FADT addresses. The platform reports 2 FACS tables (which is not allowed by ACPI specification) and the new 32-bit address favor rule forces OSPMs to use the FACS table reported via FADT's X_FIRMWARE_CTRL field. The root cause of the reported bug might be one of the followings: 1. BIOS may favor the 64-bit firmware waking vector address when the version of the FACS is greater than 0 and Linux currently only supports resuming from the real mode, so the 64-bit firmware waking vector has never been set and might be invalid to BIOS while the commit enables higher version FACS. 2. BIOS may favor the FACS reported via the "FIRMWARE_CTRL" field in the FADT while the commit doesn't set the firmware waking vector address of the FACS reported by "FIRMWARE_CTRL", it only sets the firware waking vector address of the FACS reported by "X_FIRMWARE_CTRL". This patch excludes the cases that can trigger the bugs caused by the root cause 1. ACPI specification says: A. 32-bit FACS address (FIRMWARE_CTRL field in FADT): Physical memory address of the FACS, where OSPM and firmware exchange control information. If the X_FIRMWARE_CTRL field contains a non zero value then this field must be zero. A zero value indicates that no FACS is specified by this field. B. 64-bit FACS address (X_FIRMWARE_CTRL field in FADT): 64bit physical memory address of the FACS. This field is used when the physical address of the FACS is above 4GB. If the FIRMWARE_CTRL field contains a non zero value then this field must be zero. A zero value indicates that no FACS is specified by this field. Thus the 32bit and 64bit firmware waking vector should indicate completely different resuming environment - real mode (1MB addressable) and non real mode (4GB+ addressable) and currently Linux only supports resuming from real mode. This patch enables 64-bit firmware waking vector for selected FACS via new acpi_set_firmware_waking_vectors() API so that it's up to OSPMs to determine which resuming mode should be used by BIOS and ACPICA changes won't trigger the bugs caused by the root cause 1. Lv Zheng. Link: https://bugzilla.kernel.org/show_bug.cgi?id=74021 Link: https://github.com/acpica/acpica/commit/7aa598d7 Reported-and-tested-by: Oswald Buddenhagen Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/hwxfsleep.c | 71 ++++++++++++++++++++++++++++++----------- include/acpi/acpixf.h | 8 +++-- 2 files changed, 59 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/hwxfsleep.c b/drivers/acpi/acpica/hwxfsleep.c index 82e310b94ae4..25cd9783b640 100644 --- a/drivers/acpi/acpica/hwxfsleep.c +++ b/drivers/acpi/acpica/hwxfsleep.c @@ -72,6 +72,7 @@ static struct acpi_sleep_functions acpi_sleep_dispatch[] = { /* * These functions are removed for the ACPI_REDUCED_HARDWARE case: + * acpi_set_firmware_waking_vectors * acpi_set_firmware_waking_vector * acpi_set_firmware_waking_vector64 * acpi_enter_sleep_state_s4bios @@ -80,20 +81,24 @@ static struct acpi_sleep_functions acpi_sleep_dispatch[] = { #if (!ACPI_REDUCED_HARDWARE) /******************************************************************************* * - * FUNCTION: acpi_set_firmware_waking_vector + * FUNCTION: acpi_set_firmware_waking_vectors * * PARAMETERS: physical_address - 32-bit physical address of ACPI real mode * entry point. + * physical_address64 - 64-bit physical address of ACPI protected + * mode entry point. * * RETURN: Status * - * DESCRIPTION: Sets the 32-bit firmware_waking_vector field of the FACS + * DESCRIPTION: Sets the firmware_waking_vector fields of the FACS * ******************************************************************************/ -acpi_status acpi_set_firmware_waking_vector(u32 physical_address) +acpi_status +acpi_set_firmware_waking_vectors(acpi_physical_address physical_address, + acpi_physical_address physical_address64) { - ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector); + ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vectors); /* @@ -106,17 +111,51 @@ acpi_status acpi_set_firmware_waking_vector(u32 physical_address) /* Set the 32-bit vector */ - acpi_gbl_FACS->firmware_waking_vector = physical_address; + acpi_gbl_FACS->firmware_waking_vector = (u32)physical_address; - /* Clear the 64-bit vector if it exists */ + if (acpi_gbl_FACS->length > 32) { + if (acpi_gbl_FACS->version >= 1) { - if ((acpi_gbl_FACS->length > 32) && (acpi_gbl_FACS->version >= 1)) { - acpi_gbl_FACS->xfirmware_waking_vector = 0; + /* Set the 64-bit vector */ + + acpi_gbl_FACS->xfirmware_waking_vector = + physical_address64; + } else { + /* Clear the 64-bit vector if it exists */ + + acpi_gbl_FACS->xfirmware_waking_vector = 0; + } } return_ACPI_STATUS(AE_OK); } +ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vectors) + +/******************************************************************************* + * + * FUNCTION: acpi_set_firmware_waking_vector + * + * PARAMETERS: physical_address - 32-bit physical address of ACPI real mode + * entry point. + * + * RETURN: Status + * + * DESCRIPTION: Sets the 32-bit firmware_waking_vector field of the FACS + * + ******************************************************************************/ +acpi_status acpi_set_firmware_waking_vector(u32 physical_address) +{ + acpi_status status; + + ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector); + + status = acpi_set_firmware_waking_vectors((acpi_physical_address) + physical_address, 0); + + return_ACPI_STATUS(status); +} + ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector) #if ACPI_MACHINE_WIDTH == 64 @@ -136,19 +175,15 @@ ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector) ******************************************************************************/ acpi_status acpi_set_firmware_waking_vector64(u64 physical_address) { - ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector64); - - /* Determine if the 64-bit vector actually exists */ + acpi_status status; - if ((acpi_gbl_FACS->length <= 32) || (acpi_gbl_FACS->version < 1)) { - return_ACPI_STATUS(AE_NOT_EXIST); - } + ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector64); - /* Clear 32-bit vector, set the 64-bit X_ vector */ + status = acpi_set_firmware_waking_vectors(0, + (acpi_physical_address) + physical_address); - acpi_gbl_FACS->firmware_waking_vector = 0; - acpi_gbl_FACS->xfirmware_waking_vector = physical_address; - return_ACPI_STATUS(AE_OK); + return_ACPI_STATUS(status); } ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector64) diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index d68f1cd39c49..821095ce5af7 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -814,8 +814,12 @@ ACPI_EXTERNAL_RETURN_STATUS(acpi_status ACPI_EXTERNAL_RETURN_STATUS(acpi_status acpi_leave_sleep_state(u8 sleep_state)) ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status - acpi_set_firmware_waking_vector(u32 - physical_address)) + acpi_set_firmware_waking_vectors + (acpi_physical_address physical_address, + acpi_physical_address physical_address64)) +ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status + acpi_set_firmware_waking_vector(u32 + physical_address)) #if ACPI_MACHINE_WIDTH == 64 ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_set_firmware_waking_vector64(u64 -- cgit v1.2.3-70-g09d2 From c04e1fb4396d27f18296db0f914760fa7fe8223a Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 1 Jul 2015 14:43:11 +0800 Subject: ACPICA: Tables: Enable both 32-bit and 64-bit FACS ACPICA commit f7b86f35416e3d1f71c3d816ff5075ddd33ed486 The following commit is reported to have broken s2ram on some platforms: Commit: 0249ed2444d65d65fc3f3f64f398f1ad0b7e54cd ACPICA: Add option to favor 32-bit FADT addresses. The platform reports 2 FACS tables (which is not allowed by ACPI specification) and the new 32-bit address favor rule forces OSPMs to use the FACS table reported via FADT's X_FIRMWARE_CTRL field. The root cause of the reported bug might be one of the followings: 1. BIOS may favor the 64-bit firmware waking vector address when the version of the FACS is greater than 0 and Linux currently only supports resuming from the real mode, so the 64-bit firmware waking vector has never been set and might be invalid to BIOS while the commit enables higher version FACS. 2. BIOS may favor the FACS reported via the "FIRMWARE_CTRL" field in the FADT while the commit doesn't set the firmware waking vector address of the FACS reported by "FIRMWARE_CTRL", it only sets the firware waking vector address of the FACS reported by "X_FIRMWARE_CTRL". This patch excludes the cases that can trigger the bugs caused by the root cause 2. There is no handshaking mechanism can be used by OSPM to tell BIOS which FACS is currently used. Thus the FACS reported by "FIRMWARE_CTRL" may still be used by BIOS and the 0 value of the 32-bit firmware waking vector might trigger such failure. This patch tries to favor 32bit FACS address in another way where both the FACS reported by "FIRMWARE_CTRL" and the FACS reported by "X_FIRMWARE_CTRL" are loaded so that further commit can set firmware waking vector in the both tables to ensure we can exclude the cases that trigger the bugs caused by the root cause 2. The exclusion is split into 2 commits as this commit is also useful for dumping more ACPI tables, it won't get reverted when such exclusion is no longer necessary. Lv Zheng. Link: https://bugzilla.kernel.org/show_bug.cgi?id=74021 Link: https://github.com/acpica/acpica/commit/f7b86f35 Cc: 3.14.1+ # 3.14.1+ Reported-and-tested-by: Oswald Buddenhagen Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/aclocal.h | 1 + drivers/acpi/acpica/tbfadt.c | 21 +++++++++++++-------- drivers/acpi/acpica/tbutils.c | 34 +++++++++++++++++++++++----------- drivers/acpi/acpica/tbxfload.c | 3 ++- include/acpi/acpixf.h | 9 +++++++++ 5 files changed, 48 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index ffdb956391f6..bc600969c6a1 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -213,6 +213,7 @@ struct acpi_table_list { #define ACPI_TABLE_INDEX_DSDT (0) #define ACPI_TABLE_INDEX_FACS (1) +#define ACPI_TABLE_INDEX_X_FACS (2) struct acpi_find_context { char *search_for; diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c index 7d2486005e3f..05be59c772c7 100644 --- a/drivers/acpi/acpica/tbfadt.c +++ b/drivers/acpi/acpica/tbfadt.c @@ -350,9 +350,18 @@ void acpi_tb_parse_fadt(u32 table_index) /* If Hardware Reduced flag is set, there is no FACS */ if (!acpi_gbl_reduced_hardware) { - acpi_tb_install_fixed_table((acpi_physical_address) - acpi_gbl_FADT.Xfacs, ACPI_SIG_FACS, - ACPI_TABLE_INDEX_FACS); + if (acpi_gbl_FADT.facs) { + acpi_tb_install_fixed_table((acpi_physical_address) + acpi_gbl_FADT.facs, + ACPI_SIG_FACS, + ACPI_TABLE_INDEX_FACS); + } + if (acpi_gbl_FADT.Xfacs) { + acpi_tb_install_fixed_table((acpi_physical_address) + acpi_gbl_FADT.Xfacs, + ACPI_SIG_FACS, + ACPI_TABLE_INDEX_X_FACS); + } } } @@ -491,13 +500,9 @@ static void acpi_tb_convert_fadt(void) acpi_gbl_FADT.header.length = sizeof(struct acpi_table_fadt); /* - * Expand the 32-bit FACS and DSDT addresses to 64-bit as necessary. + * Expand the 32-bit DSDT addresses to 64-bit as necessary. * Later ACPICA code will always use the X 64-bit field. */ - acpi_gbl_FADT.Xfacs = acpi_tb_select_address("FACS", - acpi_gbl_FADT.facs, - acpi_gbl_FADT.Xfacs); - acpi_gbl_FADT.Xdsdt = acpi_tb_select_address("DSDT", acpi_gbl_FADT.dsdt, acpi_gbl_FADT.Xdsdt); diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index 6559a58439c5..2fb1afaacc6d 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -68,7 +68,8 @@ acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size); acpi_status acpi_tb_initialize_facs(void) { - acpi_status status; + struct acpi_table_facs *facs32; + struct acpi_table_facs *facs64; /* If Hardware Reduced flag is set, there is no FACS */ @@ -77,11 +78,22 @@ acpi_status acpi_tb_initialize_facs(void) return (AE_OK); } - status = acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS, - ACPI_CAST_INDIRECT_PTR(struct - acpi_table_header, - &acpi_gbl_FACS)); - return (status); + (void)acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS, + ACPI_CAST_INDIRECT_PTR(struct + acpi_table_header, + &facs32)); + (void)acpi_get_table_by_index(ACPI_TABLE_INDEX_X_FACS, + ACPI_CAST_INDIRECT_PTR(struct + acpi_table_header, + &facs64)); + + if (acpi_gbl_use32_bit_facs_addresses) { + acpi_gbl_FACS = facs32 ? facs32 : facs64; + } else { + acpi_gbl_FACS = facs64 ? facs64 : facs32; + } + + return (AE_OK); } #endif /* !ACPI_REDUCED_HARDWARE */ @@ -101,7 +113,7 @@ acpi_status acpi_tb_initialize_facs(void) u8 acpi_tb_tables_loaded(void) { - if (acpi_gbl_root_table_list.current_table_count >= 3) { + if (acpi_gbl_root_table_list.current_table_count >= 4) { return (TRUE); } @@ -357,11 +369,11 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address) table_entry = ACPI_ADD_PTR(u8, table, sizeof(struct acpi_table_header)); /* - * First two entries in the table array are reserved for the DSDT - * and FACS, which are not actually present in the RSDT/XSDT - they - * come from the FADT + * First three entries in the table array are reserved for the DSDT + * and 32bit/64bit FACS, which are not actually present in the + * RSDT/XSDT - they come from the FADT */ - acpi_gbl_root_table_list.current_table_count = 2; + acpi_gbl_root_table_list.current_table_count = 3; /* Initialize the root table array from the RSDT/XSDT */ diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c index aadb3002a2dd..b63e35d6d1bf 100644 --- a/drivers/acpi/acpica/tbxfload.c +++ b/drivers/acpi/acpica/tbxfload.c @@ -166,7 +166,8 @@ static acpi_status acpi_tb_load_namespace(void) (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); for (i = 0; i < acpi_gbl_root_table_list.current_table_count; ++i) { - if ((!ACPI_COMPARE_NAME + if (!acpi_gbl_root_table_list.tables[i].address || + (!ACPI_COMPARE_NAME (&(acpi_gbl_root_table_list.tables[i].signature), ACPI_SIG_SSDT) && diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 821095ce5af7..445fd1e1688c 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -199,6 +199,15 @@ ACPI_INIT_GLOBAL(u8, acpi_gbl_do_not_use_xsdt, FALSE); */ ACPI_INIT_GLOBAL(u8, acpi_gbl_use32_bit_fadt_addresses, TRUE); +/* + * Optionally use 32-bit FACS table addresses. + * It is reported that some platforms fail to resume from system suspending + * if 64-bit FACS table address is selected: + * https://bugzilla.kernel.org/show_bug.cgi?id=74021 + * Default is TRUE, favor the 32-bit addresses. + */ +ACPI_INIT_GLOBAL(u8, acpi_gbl_use32_bit_facs_addresses, TRUE); + /* * Optionally truncate I/O addresses to 16 bits. Provides compatibility * with other ACPI implementations. NOTE: During ACPICA initialization, -- cgit v1.2.3-70-g09d2 From f06147f9fbf134c0258bd53aebeb4ed5efea5a25 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 1 Jul 2015 14:43:18 +0800 Subject: ACPICA: Hardware: Enable firmware waking vector for both 32-bit and 64-bit FACS ACPICA commit 368eb60778b27b6ae94d3658ddc902ca1342a963 ACPICA commit 70f62a80d65515e1285fdeeb50d94ee6f07df4bd ACPICA commit a04dbfa308a48ab0b2d10519c54a6c533c5c8949 ACPICA commit ebd544ed24c5a4faba11f265e228b7a821a729f5 The following commit is reported to have broken s2ram on some platforms: Commit: 0249ed2444d65d65fc3f3f64f398f1ad0b7e54cd ACPICA: Add option to favor 32-bit FADT addresses. The platform reports 2 FACS tables (which is not allowed by ACPI specification) and the new 32-bit address favor rule forces OSPMs to use the FACS table reported via FADT's X_FIRMWARE_CTRL field. The root cause of the reported bug might be one of the followings: 1. BIOS may favor the 64-bit firmware waking vector address when the version of the FACS is greater than 0 and Linux currently only supports resuming from the real mode, so the 64-bit firmware waking vector has never been set and might be invalid to BIOS while the commit enables higher version FACS. 2. BIOS may favor the FACS reported via the "FIRMWARE_CTRL" field in the FADT while the commit doesn't set the firmware waking vector address of the FACS reported by "FIRMWARE_CTRL", it only sets the firware waking vector address of the FACS reported by "X_FIRMWARE_CTRL". This patch excludes the cases that can trigger the bugs caused by the root cause 2. There is no handshaking mechanism can be used by OSPM to tell BIOS which FACS is currently used. Thus the FACS reported by "FIRMWARE_CTRL" may still be used by BIOS and the 0 value of the 32-bit firmware waking vector might trigger such failure. This patch enables the firmware waking vectors for both 32bit/64bit FACS tables in order to ensure we can exclude the cases that trigger the bugs caused by the root cause 2. The exclusion is split into 2 commits so that if it turns out not to be necessary, this single commit can be reverted without affecting the useful one. Lv Zheng, Bob Moore. Link: https://bugzilla.kernel.org/show_bug.cgi?id=74021 Link: https://github.com/acpica/acpica/commit/368eb607 Link: https://github.com/acpica/acpica/commit/70f62a80 Link: https://github.com/acpica/acpica/commit/a04dbfa3 Link: https://github.com/acpica/acpica/commit/ebd544ed Reported-and-tested-by: Oswald Buddenhagen Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acglobal.h | 2 ++ drivers/acpi/acpica/hwxfsleep.c | 74 ++++++++++++++++++++++++++++++++++------- drivers/acpi/acpica/tbutils.c | 17 +++++----- 3 files changed, 73 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index a0c478784314..53f96a370762 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -61,6 +61,8 @@ ACPI_GLOBAL(struct acpi_table_header, acpi_gbl_original_dsdt_header); #if (!ACPI_REDUCED_HARDWARE) ACPI_GLOBAL(struct acpi_table_facs *, acpi_gbl_FACS); +ACPI_GLOBAL(struct acpi_table_facs *, acpi_gbl_facs32); +ACPI_GLOBAL(struct acpi_table_facs *, acpi_gbl_facs64); #endif /* !ACPI_REDUCED_HARDWARE */ diff --git a/drivers/acpi/acpica/hwxfsleep.c b/drivers/acpi/acpica/hwxfsleep.c index 25cd9783b640..52dfd0d050fa 100644 --- a/drivers/acpi/acpica/hwxfsleep.c +++ b/drivers/acpi/acpica/hwxfsleep.c @@ -50,6 +50,13 @@ ACPI_MODULE_NAME("hwxfsleep") /* Local prototypes */ +#if (!ACPI_REDUCED_HARDWARE) +static acpi_status +acpi_hw_set_firmware_waking_vectors(struct acpi_table_facs *facs, + acpi_physical_address physical_address, + acpi_physical_address physical_address64); +#endif + static acpi_status acpi_hw_sleep_dispatch(u8 sleep_state, u32 function_id); /* @@ -81,9 +88,10 @@ static struct acpi_sleep_functions acpi_sleep_dispatch[] = { #if (!ACPI_REDUCED_HARDWARE) /******************************************************************************* * - * FUNCTION: acpi_set_firmware_waking_vectors + * FUNCTION: acpi_hw_set_firmware_waking_vectors * - * PARAMETERS: physical_address - 32-bit physical address of ACPI real mode + * PARAMETERS: facs - Pointer to FACS table + * physical_address - 32-bit physical address of ACPI real mode * entry point. * physical_address64 - 64-bit physical address of ACPI protected * mode entry point. @@ -94,11 +102,12 @@ static struct acpi_sleep_functions acpi_sleep_dispatch[] = { * ******************************************************************************/ -acpi_status -acpi_set_firmware_waking_vectors(acpi_physical_address physical_address, - acpi_physical_address physical_address64) +static acpi_status +acpi_hw_set_firmware_waking_vectors(struct acpi_table_facs *facs, + acpi_physical_address physical_address, + acpi_physical_address physical_address64) { - ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vectors); + ACPI_FUNCTION_TRACE(acpi_hw_set_firmware_waking_vectors); /* @@ -111,25 +120,66 @@ acpi_set_firmware_waking_vectors(acpi_physical_address physical_address, /* Set the 32-bit vector */ - acpi_gbl_FACS->firmware_waking_vector = (u32)physical_address; + facs->firmware_waking_vector = (u32)physical_address; - if (acpi_gbl_FACS->length > 32) { - if (acpi_gbl_FACS->version >= 1) { + if (facs->length > 32) { + if (facs->version >= 1) { /* Set the 64-bit vector */ - acpi_gbl_FACS->xfirmware_waking_vector = - physical_address64; + facs->xfirmware_waking_vector = physical_address64; } else { /* Clear the 64-bit vector if it exists */ - acpi_gbl_FACS->xfirmware_waking_vector = 0; + facs->xfirmware_waking_vector = 0; } } return_ACPI_STATUS(AE_OK); } +/******************************************************************************* + * + * FUNCTION: acpi_set_firmware_waking_vectors + * + * PARAMETERS: physical_address - 32-bit physical address of ACPI real mode + * entry point. + * physical_address64 - 64-bit physical address of ACPI protected + * mode entry point. + * + * RETURN: Status + * + * DESCRIPTION: Sets the firmware_waking_vector fields of the FACS + * + ******************************************************************************/ + +acpi_status +acpi_set_firmware_waking_vectors(acpi_physical_address physical_address, + acpi_physical_address physical_address64) +{ + + ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vectors); + + /* If Hardware Reduced flag is set, there is no FACS */ + + if (acpi_gbl_reduced_hardware) { + return_ACPI_STATUS (AE_OK); + } + + if (acpi_gbl_facs32) { + (void)acpi_hw_set_firmware_waking_vectors(acpi_gbl_facs32, + physical_address, + physical_address64); + } + if (acpi_gbl_facs64) { + (void)acpi_hw_set_firmware_waking_vectors(acpi_gbl_facs64, + physical_address, + physical_address64); + } + + return_ACPI_STATUS(AE_OK); +} + ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vectors) /******************************************************************************* diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index 2fb1afaacc6d..2bb6a117c840 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -68,8 +68,6 @@ acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size); acpi_status acpi_tb_initialize_facs(void) { - struct acpi_table_facs *facs32; - struct acpi_table_facs *facs64; /* If Hardware Reduced flag is set, there is no FACS */ @@ -81,18 +79,21 @@ acpi_status acpi_tb_initialize_facs(void) (void)acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS, ACPI_CAST_INDIRECT_PTR(struct acpi_table_header, - &facs32)); + &acpi_gbl_facs32)); (void)acpi_get_table_by_index(ACPI_TABLE_INDEX_X_FACS, ACPI_CAST_INDIRECT_PTR(struct acpi_table_header, - &facs64)); + &acpi_gbl_facs64)); - if (acpi_gbl_use32_bit_facs_addresses) { - acpi_gbl_FACS = facs32 ? facs32 : facs64; - } else { - acpi_gbl_FACS = facs64 ? facs64 : facs32; + if (acpi_gbl_facs64 + && (!acpi_gbl_facs32 || !acpi_gbl_use32_bit_facs_addresses)) { + acpi_gbl_FACS = acpi_gbl_facs64; + } else if (acpi_gbl_facs32) { + acpi_gbl_FACS = acpi_gbl_facs32; } + /* If there is no FACS, just continue. There was already an error msg */ + return (AE_OK); } #endif /* !ACPI_REDUCED_HARDWARE */ -- cgit v1.2.3-70-g09d2 From c04be18448355441a0c424362df65b6422e27bda Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 1 Jul 2015 14:43:26 +0800 Subject: ACPICA: Tables: Fix an issue that FACS initialization is performed twice ACPICA commit 90f5332a15e9d9ba83831ca700b2b9f708274658 This patch adds a new FACS initialization flag for acpi_tb_initialize(). acpi_enable_subsystem() might be invoked several times in OS bootup process, and we don't want FACS initialization to be invoked twice. Lv Zheng. Link: https://github.com/acpica/acpica/commit/90f5332a Cc: All applicable # All applicable Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/utxfinit.c | 10 ++++++---- include/acpi/actypes.h | 1 + 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/utxfinit.c b/drivers/acpi/acpica/utxfinit.c index 083a76891889..42a32a66ef22 100644 --- a/drivers/acpi/acpica/utxfinit.c +++ b/drivers/acpi/acpica/utxfinit.c @@ -179,10 +179,12 @@ acpi_status __init acpi_enable_subsystem(u32 flags) * Obtain a permanent mapping for the FACS. This is required for the * Global Lock and the Firmware Waking Vector */ - status = acpi_tb_initialize_facs(); - if (ACPI_FAILURE(status)) { - ACPI_WARNING((AE_INFO, "Could not map the FACS table")); - return_ACPI_STATUS(status); + if (!(flags & ACPI_NO_FACS_INIT)) { + status = acpi_tb_initialize_facs(); + if (ACPI_FAILURE(status)) { + ACPI_WARNING((AE_INFO, "Could not map the FACS table")); + return_ACPI_STATUS(status); + } } #endif /* !ACPI_REDUCED_HARDWARE */ diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index 63fd7f5e9fb3..ff0b53e128ee 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -568,6 +568,7 @@ typedef u64 acpi_integer; #define ACPI_NO_ACPI_ENABLE 0x10 #define ACPI_NO_DEVICE_INIT 0x20 #define ACPI_NO_OBJECT_INIT 0x40 +#define ACPI_NO_FACS_INIT 0x80 /* * Initialization state -- cgit v1.2.3-70-g09d2 From f65358e5724890ef473d28762f6de0f3284b146e Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Wed, 1 Jul 2015 14:44:04 +0800 Subject: ACPICA: Utilities: Add _CLS processing ACPICA commit 9a2b638acb3a7215209432e070c6bd0312374229 ACPI Device object often contains a _CLS object to supply PCI-defined class code for the device. This patch introduces logic to process the _CLS object. Suravee Suthikulpanit, Lv Zheng. Link: https://github.com/acpica/acpica/commit/9a2b638a Acked-by: Mika Westerberg Reviewed-by: Hanjun Guo Signed-off-by: Suravee Suthikulpanit Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acinterp.h | 2 + drivers/acpi/acpica/acutils.h | 4 ++ drivers/acpi/acpica/exutils.c | 32 +++++++++++++++ drivers/acpi/acpica/nsxfname.c | 23 +++++++++-- drivers/acpi/acpica/utids.c | 91 +++++++++++++++++++++++++++++++++++++++++- include/acpi/acnames.h | 1 + include/acpi/actypes.h | 24 ++++++----- 7 files changed, 164 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/acinterp.h b/drivers/acpi/acpica/acinterp.h index 1886bde54b5d..7ac98000b46b 100644 --- a/drivers/acpi/acpica/acinterp.h +++ b/drivers/acpi/acpica/acinterp.h @@ -468,6 +468,8 @@ void acpi_ex_eisa_id_to_string(char *dest, u64 compressed_id); void acpi_ex_integer_to_string(char *dest, u64 value); +void acpi_ex_pci_cls_to_string(char *dest, u8 class_code[3]); + u8 acpi_is_valid_space_id(u8 space_id); /* diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index d49f5c7a20d9..6391c9706e84 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -430,6 +430,10 @@ acpi_status acpi_ut_execute_CID(struct acpi_namespace_node *device_node, struct acpi_pnp_device_id_list ** return_cid_list); +acpi_status +acpi_ut_execute_CLS(struct acpi_namespace_node *device_node, + struct acpi_pnp_device_id **return_id); + /* * utlock - reader/writer locks */ diff --git a/drivers/acpi/acpica/exutils.c b/drivers/acpi/acpica/exutils.c index 3f4225e95d93..30c3f464fda5 100644 --- a/drivers/acpi/acpica/exutils.c +++ b/drivers/acpi/acpica/exutils.c @@ -378,6 +378,38 @@ void acpi_ex_integer_to_string(char *out_string, u64 value) } } +/******************************************************************************* + * + * FUNCTION: acpi_ex_pci_cls_to_string + * + * PARAMETERS: out_string - Where to put the converted string (7 bytes) + * PARAMETERS: class_code - PCI class code to be converted (3 bytes) + * + * RETURN: None + * + * DESCRIPTION: Convert 3-bytes PCI class code to string representation. + * Return buffer must be large enough to hold the string. The + * string returned is always exactly of length + * ACPI_PCICLS_STRING_SIZE (includes null terminator). + * + ******************************************************************************/ + +void acpi_ex_pci_cls_to_string(char *out_string, u8 class_code[3]) +{ + + ACPI_FUNCTION_ENTRY(); + + /* All 3 bytes are hexadecimal */ + + out_string[0] = acpi_ut_hex_to_ascii_char((u64)class_code[0], 4); + out_string[1] = acpi_ut_hex_to_ascii_char((u64)class_code[0], 0); + out_string[2] = acpi_ut_hex_to_ascii_char((u64)class_code[1], 4); + out_string[3] = acpi_ut_hex_to_ascii_char((u64)class_code[1], 0); + out_string[4] = acpi_ut_hex_to_ascii_char((u64)class_code[2], 4); + out_string[5] = acpi_ut_hex_to_ascii_char((u64)class_code[2], 0); + out_string[6] = 0; +} + /******************************************************************************* * * FUNCTION: acpi_is_valid_space_id diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index d66c326485d8..dc0836a9cf17 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c @@ -260,7 +260,7 @@ static char *acpi_ns_copy_device_id(struct acpi_pnp_device_id *dest, * control methods (Such as in the case of a device.) * * For Device and Processor objects, run the Device _HID, _UID, _CID, _SUB, - * _STA, _ADR, _sx_w, and _sx_d methods. + * _CLS, _STA, _ADR, _sx_w, and _sx_d methods. * * Note: Allocates the return buffer, must be freed by the caller. * @@ -276,11 +276,12 @@ acpi_get_object_info(acpi_handle handle, struct acpi_pnp_device_id *hid = NULL; struct acpi_pnp_device_id *uid = NULL; struct acpi_pnp_device_id *sub = NULL; + struct acpi_pnp_device_id *cls = NULL; char *next_id_string; acpi_object_type type; acpi_name name; u8 param_count = 0; - u8 valid = 0; + u16 valid = 0; u32 info_size; u32 i; acpi_status status; @@ -320,7 +321,7 @@ acpi_get_object_info(acpi_handle handle, if ((type == ACPI_TYPE_DEVICE) || (type == ACPI_TYPE_PROCESSOR)) { /* * Get extra info for ACPI Device/Processor objects only: - * Run the Device _HID, _UID, _SUB, and _CID methods. + * Run the Device _HID, _UID, _SUB, _CID, and _CLS methods. * * Note: none of these methods are required, so they may or may * not be present for this device. The Info->Valid bitfield is used @@ -363,6 +364,14 @@ acpi_get_object_info(acpi_handle handle, sizeof(struct acpi_pnp_device_id_list)); valid |= ACPI_VALID_CID; } + + /* Execute the Device._CLS method */ + + status = acpi_ut_execute_CLS(node, &cls); + if (ACPI_SUCCESS(status)) { + info_size += cls->length; + valid |= ACPI_VALID_CLS; + } } /* @@ -486,6 +495,11 @@ acpi_get_object_info(acpi_handle handle, } } + if (cls) { + next_id_string = acpi_ns_copy_device_id(&info->class_code, + cls, next_id_string); + } + /* Copy the fixed-length data */ info->info_size = info_size; @@ -510,6 +524,9 @@ cleanup: if (cid_list) { ACPI_FREE(cid_list); } + if (cls) { + ACPI_FREE(cls); + } return (status); } diff --git a/drivers/acpi/acpica/utids.c b/drivers/acpi/acpica/utids.c index 27431cfc1c44..3afe07f19b9f 100644 --- a/drivers/acpi/acpica/utids.c +++ b/drivers/acpi/acpica/utids.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Module Name: utids - support for device Ids - HID, UID, CID + * Module Name: utids - support for device Ids - HID, UID, CID, SUB, CLS * *****************************************************************************/ @@ -416,3 +416,92 @@ cleanup: acpi_ut_remove_reference(obj_desc); return_ACPI_STATUS(status); } + +/******************************************************************************* + * + * FUNCTION: acpi_ut_execute_CLS + * + * PARAMETERS: device_node - Node for the device + * return_id - Where the _CLS is returned + * + * RETURN: Status + * + * DESCRIPTION: Executes the _CLS control method that returns PCI-defined + * class code of the device. The _CLS value is always a package + * containing PCI class information as a list of integers. + * The returned string has format "BBSSPP", where: + * BB = Base-class code + * SS = Sub-class code + * PP = Programming Interface code + * + ******************************************************************************/ + +acpi_status +acpi_ut_execute_CLS(struct acpi_namespace_node *device_node, + struct acpi_pnp_device_id **return_id) +{ + union acpi_operand_object *obj_desc; + union acpi_operand_object **cls_objects; + u32 count; + struct acpi_pnp_device_id *cls; + u32 length; + acpi_status status; + u8 class_code[3] = { 0, 0, 0 }; + + ACPI_FUNCTION_TRACE(ut_execute_CLS); + + status = acpi_ut_evaluate_object(device_node, METHOD_NAME__CLS, + ACPI_BTYPE_PACKAGE, &obj_desc); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + /* Get the size of the String to be returned, includes null terminator */ + + length = ACPI_PCICLS_STRING_SIZE; + cls_objects = obj_desc->package.elements; + count = obj_desc->package.count; + + if (obj_desc->common.type == ACPI_TYPE_PACKAGE) { + if (count > 0 + && cls_objects[0]->common.type == ACPI_TYPE_INTEGER) { + class_code[0] = (u8)cls_objects[0]->integer.value; + } + if (count > 1 + && cls_objects[1]->common.type == ACPI_TYPE_INTEGER) { + class_code[1] = (u8)cls_objects[1]->integer.value; + } + if (count > 2 + && cls_objects[2]->common.type == ACPI_TYPE_INTEGER) { + class_code[2] = (u8)cls_objects[2]->integer.value; + } + } + + /* Allocate a buffer for the CLS */ + + cls = + ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_pnp_device_id) + + (acpi_size) length); + if (!cls) { + status = AE_NO_MEMORY; + goto cleanup; + } + + /* Area for the string starts after PNP_DEVICE_ID struct */ + + cls->string = + ACPI_ADD_PTR(char, cls, sizeof(struct acpi_pnp_device_id)); + + /* Simply copy existing string */ + + acpi_ex_pci_cls_to_string(cls->string, class_code); + cls->length = length; + *return_id = cls; + +cleanup: + + /* On exit, we must delete the return object */ + + acpi_ut_remove_reference(obj_desc); + return_ACPI_STATUS(status); +} diff --git a/include/acpi/acnames.h b/include/acpi/acnames.h index 273de709495c..b52c0dc4b492 100644 --- a/include/acpi/acnames.h +++ b/include/acpi/acnames.h @@ -51,6 +51,7 @@ #define METHOD_NAME__BBN "_BBN" #define METHOD_NAME__CBA "_CBA" #define METHOD_NAME__CID "_CID" +#define METHOD_NAME__CLS "_CLS" #define METHOD_NAME__CRS "_CRS" #define METHOD_NAME__DDN "_DDN" #define METHOD_NAME__HID "_HID" diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index ff0b53e128ee..d791b986002a 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -1141,6 +1141,10 @@ u32 (*acpi_interface_handler) (acpi_string interface_name, u32 supported); #define ACPI_UUID_LENGTH 16 +/* Length of 3-byte PCI class code values when converted back to a string */ + +#define ACPI_PCICLS_STRING_SIZE 7 /* Includes null terminator */ + /* Structures used for device/processor HID, UID, CID, and SUB */ struct acpi_pnp_device_id { @@ -1163,7 +1167,7 @@ struct acpi_device_info { u32 name; /* ACPI object Name */ acpi_object_type type; /* ACPI object Type */ u8 param_count; /* If a method, required parameter count */ - u8 valid; /* Indicates which optional fields are valid */ + u16 valid; /* Indicates which optional fields are valid */ u8 flags; /* Miscellaneous info */ u8 highest_dstates[4]; /* _sx_d values: 0xFF indicates not valid */ u8 lowest_dstates[5]; /* _sx_w values: 0xFF indicates not valid */ @@ -1172,6 +1176,7 @@ struct acpi_device_info { struct acpi_pnp_device_id hardware_id; /* _HID value */ struct acpi_pnp_device_id unique_id; /* _UID value */ struct acpi_pnp_device_id subsystem_id; /* _SUB value */ + struct acpi_pnp_device_id class_code; /* _CLS value */ struct acpi_pnp_device_id_list compatible_id_list; /* _CID list */ }; @@ -1181,14 +1186,15 @@ struct acpi_device_info { /* Flags for Valid field above (acpi_get_object_info) */ -#define ACPI_VALID_STA 0x01 -#define ACPI_VALID_ADR 0x02 -#define ACPI_VALID_HID 0x04 -#define ACPI_VALID_UID 0x08 -#define ACPI_VALID_SUB 0x10 -#define ACPI_VALID_CID 0x20 -#define ACPI_VALID_SXDS 0x40 -#define ACPI_VALID_SXWS 0x80 +#define ACPI_VALID_STA 0x0001 +#define ACPI_VALID_ADR 0x0002 +#define ACPI_VALID_HID 0x0004 +#define ACPI_VALID_UID 0x0008 +#define ACPI_VALID_SUB 0x0010 +#define ACPI_VALID_CID 0x0020 +#define ACPI_VALID_CLS 0x0040 +#define ACPI_VALID_SXDS 0x0100 +#define ACPI_VALID_SXWS 0x0200 /* Flags for _STA return value (current_status above) */ -- cgit v1.2.3-70-g09d2 From 8f6f03610483962a9ebfaf38592909a3f0bcfa53 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 1 Jul 2015 14:44:17 +0800 Subject: ACPICA: Namespace: Add support to allow overriding objects ACPICA commit 6084e34e44565c6293f446c0202b5e59b055e351 This patch adds an "NamespaceOverride" flag in struct acpi_walk_state, and allows namespace objects to be overridden when this flag is set. Lv Zheng. Link: https://github.com/acpica/acpica/commit/6084e34e Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acnamesp.h | 1 + drivers/acpi/acpica/acstruct.h | 1 + drivers/acpi/acpica/dswload.c | 17 +++++++++++++---- drivers/acpi/acpica/nsaccess.c | 10 +++++++++- drivers/acpi/acpica/nssearch.c | 22 ++++++++++++++++++++-- 5 files changed, 44 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h index 952fbe0b7231..0dd088290d80 100644 --- a/drivers/acpi/acpica/acnamesp.h +++ b/drivers/acpi/acpica/acnamesp.h @@ -66,6 +66,7 @@ #define ACPI_NS_PREFIX_IS_SCOPE 0x10 #define ACPI_NS_EXTERNAL 0x20 #define ACPI_NS_TEMPORARY 0x40 +#define ACPI_NS_OVERRIDE_IF_FOUND 0x80 /* Flags for acpi_ns_walk_namespace */ diff --git a/drivers/acpi/acpica/acstruct.h b/drivers/acpi/acpica/acstruct.h index 87c7860b3394..44997ca02ae2 100644 --- a/drivers/acpi/acpica/acstruct.h +++ b/drivers/acpi/acpica/acstruct.h @@ -82,6 +82,7 @@ struct acpi_walk_state { u8 return_used; u8 scope_depth; u8 pass_number; /* Parse pass during table load */ + u8 namespace_override; /* Override existing objects */ u8 result_size; /* Total elements for the result stack */ u8 result_count; /* Current number of occupied elements of result stack */ u32 aml_offset; diff --git a/drivers/acpi/acpica/dswload.c b/drivers/acpi/acpica/dswload.c index 843942fb4be5..845ff44919c3 100644 --- a/drivers/acpi/acpica/dswload.c +++ b/drivers/acpi/acpica/dswload.c @@ -315,10 +315,19 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state, flags = ACPI_NS_NO_UPSEARCH; if ((walk_state->opcode != AML_SCOPE_OP) && (!(walk_state->parse_flags & ACPI_PARSE_DEFERRED_OP))) { - flags |= ACPI_NS_ERROR_IF_FOUND; - ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, - "[%s] Cannot already exist\n", - acpi_ut_get_type_name(object_type))); + if (walk_state->namespace_override) { + flags |= ACPI_NS_OVERRIDE_IF_FOUND; + ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, + "[%s] Override allowed\n", + acpi_ut_get_type_name + (object_type))); + } else { + flags |= ACPI_NS_ERROR_IF_FOUND; + ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, + "[%s] Cannot already exist\n", + acpi_ut_get_type_name + (object_type))); + } } else { ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "[%s] Both Find or Create allowed\n", diff --git a/drivers/acpi/acpica/nsaccess.c b/drivers/acpi/acpica/nsaccess.c index 24fa19a76d70..19ad0b5993d5 100644 --- a/drivers/acpi/acpica/nsaccess.c +++ b/drivers/acpi/acpica/nsaccess.c @@ -304,7 +304,9 @@ acpi_ns_lookup(union acpi_generic_state *scope_info, return_ACPI_STATUS(AE_BAD_PARAMETER); } - local_flags = flags & ~(ACPI_NS_ERROR_IF_FOUND | ACPI_NS_SEARCH_PARENT); + local_flags = flags & + ~(ACPI_NS_ERROR_IF_FOUND | ACPI_NS_OVERRIDE_IF_FOUND | + ACPI_NS_SEARCH_PARENT); *return_node = ACPI_ENTRY_NOT_FOUND; acpi_gbl_ns_lookup_count++; @@ -547,6 +549,12 @@ acpi_ns_lookup(union acpi_generic_state *scope_info, if (flags & ACPI_NS_ERROR_IF_FOUND) { local_flags |= ACPI_NS_ERROR_IF_FOUND; } + + /* Set override flag according to caller */ + + if (flags & ACPI_NS_OVERRIDE_IF_FOUND) { + local_flags |= ACPI_NS_OVERRIDE_IF_FOUND; + } } /* Extract one ACPI name from the front of the pathname */ diff --git a/drivers/acpi/acpica/nssearch.c b/drivers/acpi/acpica/nssearch.c index 4a9d4a66016e..47fbe5b33524 100644 --- a/drivers/acpi/acpica/nssearch.c +++ b/drivers/acpi/acpica/nssearch.c @@ -325,8 +325,26 @@ acpi_ns_search_and_enter(u32 target_name, * If we found it AND the request specifies that a find is an error, * return the error */ - if ((status == AE_OK) && (flags & ACPI_NS_ERROR_IF_FOUND)) { - status = AE_ALREADY_EXISTS; + if (status == AE_OK) { + + /* The node was found in the namespace */ + + /* + * If the namespace override feature is enabled for this node, + * delete any existing node. This can only happen during the + * boot stage, thus it is safe to remove the node here. + */ + if (flags & ACPI_NS_OVERRIDE_IF_FOUND) { + acpi_ns_delete_children(*return_node); + acpi_ns_remove_node(*return_node); + *return_node = ACPI_ENTRY_NOT_FOUND; + } + + /* Return an error if we don't expect to find the object */ + + else if (flags & ACPI_NS_ERROR_IF_FOUND) { + status = AE_ALREADY_EXISTS; + } } #ifdef ACPI_ASL_COMPILER if (*return_node && (*return_node)->type == ACPI_TYPE_ANY) { -- cgit v1.2.3-70-g09d2 From fe536995f2fe26fff111a9a06bf3f71e179c92cf Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 1 Jul 2015 14:44:23 +0800 Subject: ACPICA: Namespace: Add support of OSDT table ACPICA commit 27415c82fcecf467446f66d1007a0691cc5f3709 This patch adds OSDT (Override System Definition Table) support. When OSDT is loaded, conflict namespace objects will be overridden by the AML interpreter. Bob Moore, Lv Zheng. Link: https://github.com/acpica/acpica/commit/27415c82 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/nsparse.c | 7 +++++++ drivers/acpi/acpica/tbxfload.c | 6 +++++- drivers/acpi/acpica/utmisc.c | 3 ++- include/acpi/actbl.h | 1 + 4 files changed, 15 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/nsparse.c b/drivers/acpi/acpica/nsparse.c index c95a119767b5..57a4cfe547e4 100644 --- a/drivers/acpi/acpica/nsparse.c +++ b/drivers/acpi/acpica/nsparse.c @@ -117,6 +117,13 @@ acpi_ns_one_complete_parse(u32 pass_number, (u8) pass_number); } + /* Found OSDT table, enable the namespace override feature */ + + if (ACPI_COMPARE_NAME(table->signature, ACPI_SIG_OSDT) && + pass_number == ACPI_IMODE_LOAD_PASS1) { + walk_state->namespace_override = TRUE; + } + if (ACPI_FAILURE(status)) { acpi_ds_delete_walk_state(walk_state); goto cleanup; diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c index b63e35d6d1bf..960bd999a6b3 100644 --- a/drivers/acpi/acpica/tbxfload.c +++ b/drivers/acpi/acpica/tbxfload.c @@ -173,7 +173,11 @@ static acpi_status acpi_tb_load_namespace(void) && !ACPI_COMPARE_NAME(& (acpi_gbl_root_table_list.tables[i]. - signature), ACPI_SIG_PSDT)) + signature), ACPI_SIG_PSDT) + && + !ACPI_COMPARE_NAME(& + (acpi_gbl_root_table_list.tables[i]. + signature), ACPI_SIG_OSDT)) || ACPI_FAILURE(acpi_tb_validate_table (&acpi_gbl_root_table_list.tables[i]))) { diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c index cbb7034d28d8..28099e230008 100644 --- a/drivers/acpi/acpica/utmisc.c +++ b/drivers/acpi/acpica/utmisc.c @@ -97,7 +97,8 @@ u8 acpi_ut_is_aml_table(struct acpi_table_header *table) if (ACPI_COMPARE_NAME(table->signature, ACPI_SIG_DSDT) || ACPI_COMPARE_NAME(table->signature, ACPI_SIG_PSDT) || - ACPI_COMPARE_NAME(table->signature, ACPI_SIG_SSDT)) { + ACPI_COMPARE_NAME(table->signature, ACPI_SIG_SSDT) || + ACPI_COMPARE_NAME(table->signature, ACPI_SIG_OSDT)) { return (TRUE); } diff --git a/include/acpi/actbl.h b/include/acpi/actbl.h index cb8a6b97ceda..2d5faf508cad 100644 --- a/include/acpi/actbl.h +++ b/include/acpi/actbl.h @@ -65,6 +65,7 @@ #define ACPI_SIG_DSDT "DSDT" /* Differentiated System Description Table */ #define ACPI_SIG_FADT "FACP" /* Fixed ACPI Description Table */ #define ACPI_SIG_FACS "FACS" /* Firmware ACPI Control Structure */ +#define ACPI_SIG_OSDT "OSDT" /* Override System Description Table */ #define ACPI_SIG_PSDT "PSDT" /* Persistent System Description Table */ #define ACPI_SIG_RSDP "RSD PTR " /* Root System Description Pointer */ #define ACPI_SIG_RSDT "RSDT" /* Root System Description Table */ -- cgit v1.2.3-70-g09d2 From 8ea98655775e904ea406d74a887d0b2254651b5a Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 1 Jul 2015 14:44:31 +0800 Subject: ACPICA: Namespace: Change namespace override to avoid node deletion ACPICA commit c0ce529e1fbb8ec47d2522a3aa10f3ab77e16e41 There is no reference counting implemented for struct acpi_namespace_node, so it is currently not removable during runtime. This patch changes the namespace override code to keep the old struct acpi_namespace_node undeleted so that the override mechanism can happen during runtime. Bob Moore. Link: https://github.com/acpica/acpica/commit/c0ce529e Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/nssearch.c | 23 +++++++++++++++++++---- include/acpi/acpixf.h | 5 +++++ 2 files changed, 24 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/nssearch.c b/drivers/acpi/acpica/nssearch.c index 47fbe5b33524..d73904013830 100644 --- a/drivers/acpi/acpica/nssearch.c +++ b/drivers/acpi/acpica/nssearch.c @@ -331,13 +331,28 @@ acpi_ns_search_and_enter(u32 target_name, /* * If the namespace override feature is enabled for this node, - * delete any existing node. This can only happen during the - * boot stage, thus it is safe to remove the node here. + * delete any existing attached sub-object and make the node + * look like a new node that is owned by the override table. */ if (flags & ACPI_NS_OVERRIDE_IF_FOUND) { + ACPI_DEBUG_PRINT((ACPI_DB_NAMES, + "Namespace override: %4.4s pass %u type %X Owner %X\n", + ACPI_CAST_PTR(char, + &target_name), + interpreter_mode, + (*return_node)->type, + walk_state->owner_id)); + acpi_ns_delete_children(*return_node); - acpi_ns_remove_node(*return_node); - *return_node = ACPI_ENTRY_NOT_FOUND; + if (acpi_gbl_runtime_namespace_override) { + acpi_ut_remove_reference((*return_node)->object); + (*return_node)->object = NULL; + (*return_node)->owner_id = + walk_state->owner_id; + } else { + acpi_ns_remove_node(*return_node); + *return_node = ACPI_ENTRY_NOT_FOUND; + } } /* Return an error if we don't expect to find the object */ diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 213ed7ecfd8d..f6d807170346 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -228,6 +228,11 @@ ACPI_INIT_GLOBAL(u8, acpi_gbl_disable_auto_repair, FALSE); */ ACPI_INIT_GLOBAL(u8, acpi_gbl_disable_ssdt_table_install, FALSE); +/* + * Optionally enable runtime namespace override. + */ +ACPI_INIT_GLOBAL(u8, acpi_gbl_runtime_namespace_override, TRUE); + /* * We keep track of the latest version of Windows that has been requested by * the BIOS. ACPI 5.0. -- cgit v1.2.3-70-g09d2 From dc00203b6c6fb1b0ce99f37118d9a3e7a6807d7b Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Wed, 1 Jul 2015 14:44:37 +0800 Subject: ACPICA: Update for acpi_install_table memory types ACPICA commit 3f78b7fb3f98f35d62f532c1891deb748ad196c9 Physical/virtual address flags were reversed. Link: https://github.com/acpica/acpica/commit/3f78b7fb Signed-off-by: Zhang Rui Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/tbxfload.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c index 960bd999a6b3..cf56e18cdc64 100644 --- a/drivers/acpi/acpica/tbxfload.c +++ b/drivers/acpi/acpica/tbxfload.c @@ -224,9 +224,9 @@ acpi_install_table(acpi_physical_address address, u8 physical) ACPI_FUNCTION_TRACE(acpi_install_table); if (physical) { - flags = ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL; - } else { flags = ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL; + } else { + flags = ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL; } status = acpi_tb_install_standard_table(address, flags, -- cgit v1.2.3-70-g09d2 From fde175e385fc28c31a50be2608113689449a4b75 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 1 Jul 2015 14:44:44 +0800 Subject: ACPICA: Cleanup output for the ASL Debug object ACPICA commit d4a53a396fe5d384425251b0257f8d125bbed617 Especially for use of the Index operator. For buffers and strings, only output the actual byte pointed to by the index. For packages, only print the package element decoded by the index. Link: https://github.com/acpica/acpica/commit/d4a53a39 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acobject.h | 1 + drivers/acpi/acpica/exdebug.c | 42 ++++++++++++++++++++++++++++++++++++++++-- drivers/acpi/acpica/exdump.c | 9 +++++---- drivers/acpi/acpica/exoparg2.c | 4 ++++ 4 files changed, 50 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h index 3e9720e1f34f..c81d98d09cac 100644 --- a/drivers/acpi/acpica/acobject.h +++ b/drivers/acpi/acpica/acobject.h @@ -335,6 +335,7 @@ struct acpi_object_reference { void *object; /* name_op=>HANDLE to obj, index_op=>union acpi_operand_object */ struct acpi_namespace_node *node; /* ref_of or Namepath */ union acpi_operand_object **where; /* Target of Index */ + u8 *index_pointer; /* Used for Buffers and Strings */ u32 value; /* Used for Local/Arg/Index/ddb_handle */ }; diff --git a/drivers/acpi/acpica/exdebug.c b/drivers/acpi/acpica/exdebug.c index e67d0aca3fe6..815442bbd051 100644 --- a/drivers/acpi/acpica/exdebug.c +++ b/drivers/acpi/acpica/exdebug.c @@ -76,6 +76,8 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc, { u32 i; u32 timer; + union acpi_operand_object *object_desc; + u32 value; ACPI_FUNCTION_TRACE_PTR(ex_do_debug_object, source_desc); @@ -254,8 +256,44 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc, object)->object, level + 4, 0); } else { - acpi_ex_do_debug_object(source_desc->reference. - object, level + 4, 0); + object_desc = source_desc->reference.object; + value = source_desc->reference.value; + + switch (object_desc->common.type) { + case ACPI_TYPE_BUFFER: + + acpi_os_printf("Buffer[%u] = 0x%2.2X\n", + value, + *source_desc->reference. + index_pointer); + break; + + case ACPI_TYPE_STRING: + + acpi_os_printf + ("String[%u] = \"%c\" (0x%2.2X)\n", + value, + *source_desc->reference. + index_pointer, + *source_desc->reference. + index_pointer); + break; + + case ACPI_TYPE_PACKAGE: + + acpi_os_printf("Package[%u] = ", value); + acpi_ex_do_debug_object(*source_desc-> + reference.where, + level + 4, 0); + break; + + default: + + acpi_os_printf + ("Unknown Reference object type %X\n", + object_desc->common.type); + break; + } } } break; diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c index 1da52bef632e..401e7edcd419 100644 --- a/drivers/acpi/acpica/exdump.c +++ b/drivers/acpi/acpica/exdump.c @@ -224,7 +224,7 @@ static struct acpi_exdump_info acpi_ex_dump_index_field[5] = { {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(index_field.data_obj), "Data Object"} }; -static struct acpi_exdump_info acpi_ex_dump_reference[8] = { +static struct acpi_exdump_info acpi_ex_dump_reference[9] = { {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_reference), NULL}, {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(reference.class), "Class"}, {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(reference.target_type), "Target Type"}, @@ -232,6 +232,8 @@ static struct acpi_exdump_info acpi_ex_dump_reference[8] = { {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(reference.object), "Object Desc"}, {ACPI_EXD_NODE, ACPI_EXD_OFFSET(reference.node), "Node"}, {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(reference.where), "Where"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(reference.index_pointer), + "Index Pointer"}, {ACPI_EXD_REFERENCE, 0, NULL} }; @@ -1005,14 +1007,13 @@ static void acpi_ex_dump_reference_obj(union acpi_operand_object *obj_desc) } else if (obj_desc->reference.object) { if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) == ACPI_DESC_TYPE_OPERAND) { - acpi_os_printf(" Target: %p", + acpi_os_printf("%22s %p", "Target :", obj_desc->reference.object); if (obj_desc->reference.class == ACPI_REFCLASS_TABLE) { acpi_os_printf(" Table Index: %X\n", obj_desc->reference.value); } else { - acpi_os_printf(" Target: %p [%s]\n", - obj_desc->reference.object, + acpi_os_printf(" [%s]\n", acpi_ut_get_type_name(((union acpi_operand_object *) diff --git a/drivers/acpi/acpica/exoparg2.c b/drivers/acpi/acpica/exoparg2.c index fcc618aa2061..6fac5e0a698a 100644 --- a/drivers/acpi/acpica/exoparg2.c +++ b/drivers/acpi/acpica/exoparg2.c @@ -380,6 +380,8 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state) return_desc->reference.target_type = ACPI_TYPE_BUFFER_FIELD; + return_desc->reference.index_pointer = + &(operand[0]->buffer.pointer[index]); break; case ACPI_TYPE_BUFFER: @@ -391,6 +393,8 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state) return_desc->reference.target_type = ACPI_TYPE_BUFFER_FIELD; + return_desc->reference.index_pointer = + &(operand[0]->buffer.pointer[index]); break; case ACPI_TYPE_PACKAGE: -- cgit v1.2.3-70-g09d2 From 4fa4616e279df89baeb36287bbee83ab272edaed Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 1 Jul 2015 14:45:11 +0800 Subject: ACPICA: De-macroize calls to standard C library functions ACPICA commit 3b1026e0bdd3c32eb6d5d313f3ba0b1fee7597b4 ACPICA commit 00f0dc83f5cfca53b27a3213ae0d7719b88c2d6b ACPICA commit 47d22a738d0e19fd241ffe4e3e9d4e198e4afc69 Across all of ACPICA. Replace C library macros such as ACPI_STRLEN with the standard names such as strlen. The original purpose for these macros is long since obsolete. Also cast various invocations as necessary. Bob Moore, Jung-uk Kim, Lv Zheng. Link: https://github.com/acpica/acpica/commit/3b1026e0 Link: https://github.com/acpica/acpica/commit/00f0dc83 Link: https://github.com/acpica/acpica/commit/47d22a73 Signed-off-by: Bob Moore Signed-off-by: Jung-uk Kim Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acutils.h | 46 +++++++++---------- drivers/acpi/acpica/dsfield.c | 2 +- drivers/acpi/acpica/dsinit.c | 2 +- drivers/acpi/acpica/dsobject.c | 7 ++- drivers/acpi/acpica/dsutils.c | 4 +- drivers/acpi/acpica/evgpeinit.c | 2 +- drivers/acpi/acpica/exconfig.c | 2 +- drivers/acpi/acpica/exconvrt.c | 9 ++-- drivers/acpi/acpica/exfield.c | 2 +- drivers/acpi/acpica/exfldio.c | 52 +++++++++++----------- drivers/acpi/acpica/exmisc.c | 36 +++++++-------- drivers/acpi/acpica/exnames.c | 2 +- drivers/acpi/acpica/exoparg2.c | 4 +- drivers/acpi/acpica/exoparg3.c | 4 +- drivers/acpi/acpica/exregion.c | 9 ++-- drivers/acpi/acpica/exstorob.c | 18 ++++---- drivers/acpi/acpica/nsaccess.c | 6 +-- drivers/acpi/acpica/nsconvert.c | 10 ++--- drivers/acpi/acpica/nsdump.c | 2 +- drivers/acpi/acpica/nseval.c | 2 +- drivers/acpi/acpica/nsinit.c | 4 +- drivers/acpi/acpica/nsrepair2.c | 2 +- drivers/acpi/acpica/nsutils.c | 3 +- drivers/acpi/acpica/nsxfeval.c | 5 +-- drivers/acpi/acpica/nsxfname.c | 6 +-- drivers/acpi/acpica/psutils.c | 7 ++- drivers/acpi/acpica/rscreate.c | 6 +-- drivers/acpi/acpica/rsmisc.c | 8 ++-- drivers/acpi/acpica/rsutils.c | 11 +++-- drivers/acpi/acpica/rsxface.c | 8 ++-- drivers/acpi/acpica/tbdata.c | 8 ++-- drivers/acpi/acpica/tbfadt.c | 6 +-- drivers/acpi/acpica/tbfind.c | 21 +++++---- drivers/acpi/acpica/tbinstal.c | 7 ++- drivers/acpi/acpica/tbprint.c | 10 ++--- drivers/acpi/acpica/tbutils.c | 2 +- drivers/acpi/acpica/tbxface.c | 16 +++---- drivers/acpi/acpica/tbxfload.c | 4 +- drivers/acpi/acpica/utalloc.c | 6 +-- drivers/acpi/acpica/utbuffer.c | 4 +- drivers/acpi/acpica/utcache.c | 6 +-- drivers/acpi/acpica/utcopy.c | 42 ++++++++--------- drivers/acpi/acpica/utids.c | 9 ++-- drivers/acpi/acpica/utmisc.c | 6 +-- drivers/acpi/acpica/utosi.c | 9 ++-- drivers/acpi/acpica/utpredef.c | 4 +- drivers/acpi/acpica/utprint.c | 6 +-- drivers/acpi/acpica/utstring.c | 33 +++++++------- drivers/acpi/acpica/uttrack.c | 8 ++-- drivers/acpi/acpica/utxface.c | 8 ++-- include/acpi/actypes.h | 8 ++-- include/acpi/platform/acenv.h | 38 ---------------- tools/power/acpi/common/getopt.c | 4 +- .../acpi/os_specific/service_layers/oslinuxtbl.c | 6 +-- tools/power/acpi/tools/acpidump/apdump.c | 8 ++-- tools/power/acpi/tools/acpidump/apfiles.c | 12 ++--- 56 files changed, 260 insertions(+), 312 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index 6391c9706e84..ef1e51d0f038 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -210,37 +210,35 @@ void acpi_ut_subsystem_shutdown(void); */ #ifndef ACPI_USE_SYSTEM_CLIBRARY -acpi_size acpi_ut_strlen(const char *string); +acpi_size strlen(const char *string); -char *acpi_ut_strchr(const char *string, int ch); +char *strchr(const char *string, int ch); -char *acpi_ut_strcpy(char *dst_string, const char *src_string); +char *strcpy(char *dst_string, const char *src_string); -char *acpi_ut_strncpy(char *dst_string, - const char *src_string, acpi_size count); +char *strncpy(char *dst_string, const char *src_string, acpi_size count); -int acpi_ut_memcmp(const char *buffer1, const char *buffer2, acpi_size count); +int strncmp(const char *string1, const char *string2, acpi_size count); -int acpi_ut_strncmp(const char *string1, const char *string2, acpi_size count); +int strcmp(const char *string1, const char *string2); -int acpi_ut_strcmp(const char *string1, const char *string2); +char *strcat(char *dst_string, const char *src_string); -char *acpi_ut_strcat(char *dst_string, const char *src_string); +char *strncat(char *dst_string, const char *src_string, acpi_size count); -char *acpi_ut_strncat(char *dst_string, - const char *src_string, acpi_size count); +u32 strtoul(const char *string, char **terminator, u32 base); -u32 acpi_ut_strtoul(const char *string, char **terminator, u32 base); +char *strstr(char *string1, char *string2); -char *acpi_ut_strstr(char *string1, char *string2); +int memcmp(void *buffer1, void *buffer2, acpi_size count); -void *acpi_ut_memcpy(void *dest, const void *src, acpi_size count); +void *memcpy(void *dest, const void *src, acpi_size count); -void *acpi_ut_memset(void *dest, u8 value, acpi_size count); +void *memset(void *dest, int value, acpi_size count); -int acpi_ut_to_upper(int c); +int toupper(int c); -int acpi_ut_to_lower(int c); +int tolower(int c); extern const u8 _acpi_ctype[]; @@ -255,13 +253,13 @@ extern const u8 _acpi_ctype[]; #define _ACPI_UP 0x01 /* 'A'-'Z' */ #define _ACPI_XD 0x80 /* '0'-'9', 'A'-'F', 'a'-'f' */ -#define ACPI_IS_DIGIT(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_DI)) -#define ACPI_IS_SPACE(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_SP)) -#define ACPI_IS_XDIGIT(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_XD)) -#define ACPI_IS_UPPER(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_UP)) -#define ACPI_IS_LOWER(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_LO)) -#define ACPI_IS_PRINT(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_LO | _ACPI_UP | _ACPI_DI | _ACPI_XS | _ACPI_PU)) -#define ACPI_IS_ALPHA(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_LO | _ACPI_UP)) +#define isdigit(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_DI)) +#define isspace(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_SP)) +#define isxdigit(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_XD)) +#define isupper(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_UP)) +#define islower(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_LO)) +#define isprint(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_LO | _ACPI_UP | _ACPI_DI | _ACPI_XS | _ACPI_PU)) +#define isalpha(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_LO | _ACPI_UP)) #endif /* !ACPI_USE_SYSTEM_CLIBRARY */ diff --git a/drivers/acpi/acpica/dsfield.c b/drivers/acpi/acpica/dsfield.c index 43b40de90484..20de148594fd 100644 --- a/drivers/acpi/acpica/dsfield.c +++ b/drivers/acpi/acpica/dsfield.c @@ -502,7 +502,7 @@ acpi_ds_create_field(union acpi_parse_object *op, } } - ACPI_MEMSET(&info, 0, sizeof(struct acpi_create_field_info)); + memset(&info, 0, sizeof(struct acpi_create_field_info)); /* Second arg is the field flags */ diff --git a/drivers/acpi/acpica/dsinit.c b/drivers/acpi/acpica/dsinit.c index bbe74bcebbae..95779e8ec3bb 100644 --- a/drivers/acpi/acpica/dsinit.c +++ b/drivers/acpi/acpica/dsinit.c @@ -207,7 +207,7 @@ acpi_ds_initialize_objects(u32 table_index, /* Set all init info to zero */ - ACPI_MEMSET(&info, 0, sizeof(struct acpi_init_walk_info)); + memset(&info, 0, sizeof(struct acpi_init_walk_info)); info.owner_id = owner_id; info.table_index = table_index; diff --git a/drivers/acpi/acpica/dsobject.c b/drivers/acpi/acpica/dsobject.c index 4a4b2f343713..2beb7fd674ae 100644 --- a/drivers/acpi/acpica/dsobject.c +++ b/drivers/acpi/acpica/dsobject.c @@ -339,8 +339,8 @@ acpi_ds_build_internal_buffer_obj(struct acpi_walk_state *walk_state, /* Initialize buffer from the byte_list (if present) */ if (byte_list) { - ACPI_MEMCPY(obj_desc->buffer.pointer, - byte_list->named.data, byte_list_length); + memcpy(obj_desc->buffer.pointer, byte_list->named.data, + byte_list_length); } } @@ -750,8 +750,7 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state, case ACPI_TYPE_STRING: obj_desc->string.pointer = op->common.value.string; - obj_desc->string.length = - (u32)ACPI_STRLEN(op->common.value.string); + obj_desc->string.length = (u32)strlen(op->common.value.string); /* * The string is contained in the ACPI table, don't ever try diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c index deeddd6d2f05..ebc577baeaf9 100644 --- a/drivers/acpi/acpica/dsutils.c +++ b/drivers/acpi/acpica/dsutils.c @@ -572,8 +572,8 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state, obj_desc = acpi_ut_create_string_object((acpi_size) name_length); - ACPI_STRNCPY(obj_desc->string.pointer, - name_string, name_length); + strncpy(obj_desc->string.pointer, + name_string, name_length); status = AE_OK; } else { /* diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c index 8840296d5b20..ea4c0d3fca2d 100644 --- a/drivers/acpi/acpica/evgpeinit.c +++ b/drivers/acpi/acpica/evgpeinit.c @@ -377,7 +377,7 @@ acpi_ev_match_gpe_method(acpi_handle obj_handle, /* 4) The last two characters of the name are the hex GPE Number */ - gpe_number = ACPI_STRTOUL(&name[2], NULL, 16); + gpe_number = strtoul(&name[2], NULL, 16); if (gpe_number == ACPI_UINT32_MAX) { /* Conversion failed; invalid method, just ignore it */ diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c index 6e0df2b9d5a4..24a4c5c2b124 100644 --- a/drivers/acpi/acpica/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c @@ -470,7 +470,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, return_ACPI_STATUS(AE_NO_MEMORY); } - ACPI_MEMCPY(table, table_header, length); + memcpy(table, table_header, length); break; default: diff --git a/drivers/acpi/acpica/exconvrt.c b/drivers/acpi/acpica/exconvrt.c index 89a976b4ccf2..075d654c837f 100644 --- a/drivers/acpi/acpica/exconvrt.c +++ b/drivers/acpi/acpica/exconvrt.c @@ -227,9 +227,8 @@ acpi_ex_convert_to_buffer(union acpi_operand_object *obj_desc, /* Copy the integer to the buffer, LSB first */ new_buf = return_desc->buffer.pointer; - ACPI_MEMCPY(new_buf, - &obj_desc->integer.value, - acpi_gbl_integer_byte_width); + memcpy(new_buf, + &obj_desc->integer.value, acpi_gbl_integer_byte_width); break; case ACPI_TYPE_STRING: @@ -252,8 +251,8 @@ acpi_ex_convert_to_buffer(union acpi_operand_object *obj_desc, /* Copy the string to the buffer */ new_buf = return_desc->buffer.pointer; - ACPI_STRNCPY((char *)new_buf, (char *)obj_desc->string.pointer, - obj_desc->string.length); + strncpy((char *)new_buf, (char *)obj_desc->string.pointer, + obj_desc->string.length); break; default: diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c index c161dd974f74..61fd9c7b88bc 100644 --- a/drivers/acpi/acpica/exfield.c +++ b/drivers/acpi/acpica/exfield.c @@ -428,7 +428,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, } buffer = buffer_desc->buffer.pointer; - ACPI_MEMCPY(buffer, source_desc->buffer.pointer, length); + memcpy(buffer, source_desc->buffer.pointer, length); /* Lock entire transaction if requested */ diff --git a/drivers/acpi/acpica/exfldio.c b/drivers/acpi/acpica/exfldio.c index 725a3746a2df..70b7bbbb860b 100644 --- a/drivers/acpi/acpica/exfldio.c +++ b/drivers/acpi/acpica/exfldio.c @@ -416,22 +416,22 @@ acpi_ex_field_datum_io(union acpi_operand_object *obj_desc, * Copy the data from the source buffer. * Length is the field width in bytes. */ - ACPI_MEMCPY(value, - (obj_desc->buffer_field.buffer_obj)->buffer. - pointer + - obj_desc->buffer_field.base_byte_offset + - field_datum_byte_offset, - obj_desc->common_field.access_byte_width); + memcpy(value, + (obj_desc->buffer_field.buffer_obj)->buffer. + pointer + + obj_desc->buffer_field.base_byte_offset + + field_datum_byte_offset, + obj_desc->common_field.access_byte_width); } else { /* * Copy the data to the target buffer. * Length is the field width in bytes. */ - ACPI_MEMCPY((obj_desc->buffer_field.buffer_obj)->buffer. - pointer + - obj_desc->buffer_field.base_byte_offset + - field_datum_byte_offset, value, - obj_desc->common_field.access_byte_width); + memcpy((obj_desc->buffer_field.buffer_obj)->buffer. + pointer + + obj_desc->buffer_field.base_byte_offset + + field_datum_byte_offset, value, + obj_desc->common_field.access_byte_width); } status = AE_OK; @@ -703,7 +703,7 @@ acpi_ex_extract_from_field(union acpi_operand_object *obj_desc, return_ACPI_STATUS(AE_BUFFER_OVERFLOW); } - ACPI_MEMSET(buffer, 0, buffer_length); + memset(buffer, 0, buffer_length); access_bit_width = ACPI_MUL_8(obj_desc->common_field.access_byte_width); /* Handle the simple case here */ @@ -720,7 +720,7 @@ acpi_ex_extract_from_field(union acpi_operand_object *obj_desc, status = acpi_ex_field_datum_io(obj_desc, 0, &raw_datum, ACPI_READ); - ACPI_MEMCPY(buffer, &raw_datum, buffer_length); + memcpy(buffer, &raw_datum, buffer_length); } return_ACPI_STATUS(status); @@ -793,9 +793,9 @@ acpi_ex_extract_from_field(union acpi_operand_object *obj_desc, /* Write merged datum to target buffer */ - ACPI_MEMCPY(((char *)buffer) + buffer_offset, &merged_datum, - ACPI_MIN(obj_desc->common_field.access_byte_width, - buffer_length - buffer_offset)); + memcpy(((char *)buffer) + buffer_offset, &merged_datum, + ACPI_MIN(obj_desc->common_field.access_byte_width, + buffer_length - buffer_offset)); buffer_offset += obj_desc->common_field.access_byte_width; merged_datum = @@ -811,9 +811,9 @@ acpi_ex_extract_from_field(union acpi_operand_object *obj_desc, /* Write the last datum to the buffer */ - ACPI_MEMCPY(((char *)buffer) + buffer_offset, &merged_datum, - ACPI_MIN(obj_desc->common_field.access_byte_width, - buffer_length - buffer_offset)); + memcpy(((char *)buffer) + buffer_offset, &merged_datum, + ACPI_MIN(obj_desc->common_field.access_byte_width, + buffer_length - buffer_offset)); return_ACPI_STATUS(AE_OK); } @@ -878,7 +878,7 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc, * at Byte zero. All unused (upper) bytes of the * buffer will be 0. */ - ACPI_MEMCPY((char *)new_buffer, (char *)buffer, buffer_length); + memcpy((char *)new_buffer, (char *)buffer, buffer_length); buffer = new_buffer; buffer_length = required_length; } @@ -918,9 +918,9 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc, /* Get initial Datum from the input buffer */ - ACPI_MEMCPY(&raw_datum, buffer, - ACPI_MIN(obj_desc->common_field.access_byte_width, - buffer_length - buffer_offset)); + memcpy(&raw_datum, buffer, + ACPI_MIN(obj_desc->common_field.access_byte_width, + buffer_length - buffer_offset)); merged_datum = raw_datum << obj_desc->common_field.start_field_bit_offset; @@ -970,9 +970,9 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc, /* Get the next input datum from the buffer */ buffer_offset += obj_desc->common_field.access_byte_width; - ACPI_MEMCPY(&raw_datum, ((char *)buffer) + buffer_offset, - ACPI_MIN(obj_desc->common_field.access_byte_width, - buffer_length - buffer_offset)); + memcpy(&raw_datum, ((char *)buffer) + buffer_offset, + ACPI_MIN(obj_desc->common_field.access_byte_width, + buffer_length - buffer_offset)); merged_datum |= raw_datum << obj_desc->common_field.start_field_bit_offset; diff --git a/drivers/acpi/acpica/exmisc.c b/drivers/acpi/acpica/exmisc.c index b56fc9d6f48e..d02afece0f10 100644 --- a/drivers/acpi/acpica/exmisc.c +++ b/drivers/acpi/acpica/exmisc.c @@ -209,8 +209,8 @@ acpi_ex_concat_template(union acpi_operand_object *operand0, * end_tag descriptor is copied from Operand1. */ new_buf = return_desc->buffer.pointer; - ACPI_MEMCPY(new_buf, operand0->buffer.pointer, length0); - ACPI_MEMCPY(new_buf + length0, operand1->buffer.pointer, length1); + memcpy(new_buf, operand0->buffer.pointer, length0); + memcpy(new_buf + length0, operand1->buffer.pointer, length1); /* Insert end_tag and set the checksum to zero, means "ignore checksum" */ @@ -318,14 +318,14 @@ acpi_ex_do_concatenate(union acpi_operand_object *operand0, /* Copy the first integer, LSB first */ - ACPI_MEMCPY(new_buf, &operand0->integer.value, - acpi_gbl_integer_byte_width); + memcpy(new_buf, &operand0->integer.value, + acpi_gbl_integer_byte_width); /* Copy the second integer (LSB first) after the first */ - ACPI_MEMCPY(new_buf + acpi_gbl_integer_byte_width, - &local_operand1->integer.value, - acpi_gbl_integer_byte_width); + memcpy(new_buf + acpi_gbl_integer_byte_width, + &local_operand1->integer.value, + acpi_gbl_integer_byte_width); break; case ACPI_TYPE_STRING: @@ -346,9 +346,9 @@ acpi_ex_do_concatenate(union acpi_operand_object *operand0, /* Concatenate the strings */ - ACPI_STRCPY(new_buf, operand0->string.pointer); - ACPI_STRCPY(new_buf + operand0->string.length, - local_operand1->string.pointer); + strcpy(new_buf, operand0->string.pointer); + strcpy(new_buf + operand0->string.length, + local_operand1->string.pointer); break; case ACPI_TYPE_BUFFER: @@ -369,11 +369,11 @@ acpi_ex_do_concatenate(union acpi_operand_object *operand0, /* Concatenate the buffers */ - ACPI_MEMCPY(new_buf, operand0->buffer.pointer, - operand0->buffer.length); - ACPI_MEMCPY(new_buf + operand0->buffer.length, - local_operand1->buffer.pointer, - local_operand1->buffer.length); + memcpy(new_buf, operand0->buffer.pointer, + operand0->buffer.length); + memcpy(new_buf + operand0->buffer.length, + local_operand1->buffer.pointer, + local_operand1->buffer.length); break; default: @@ -660,9 +660,9 @@ acpi_ex_do_logical_op(u16 opcode, /* Lexicographic compare: compare the data bytes */ - compare = ACPI_MEMCMP(operand0->buffer.pointer, - local_operand1->buffer.pointer, - (length0 > length1) ? length1 : length0); + compare = memcmp(operand0->buffer.pointer, + local_operand1->buffer.pointer, + (length0 > length1) ? length1 : length0); switch (opcode) { case AML_LEQUAL_OP: /* LEqual (Operand0, Operand1) */ diff --git a/drivers/acpi/acpica/exnames.c b/drivers/acpi/acpica/exnames.c index 453b00c30177..20e87813c7d7 100644 --- a/drivers/acpi/acpica/exnames.c +++ b/drivers/acpi/acpica/exnames.c @@ -192,7 +192,7 @@ static acpi_status acpi_ex_name_segment(u8 ** in_aml_address, char *name_string) char_buf[4] = '\0'; if (name_string) { - ACPI_STRCAT(name_string, char_buf); + strcat(name_string, char_buf); ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Appended to - %s\n", name_string)); } else { diff --git a/drivers/acpi/acpica/exoparg2.c b/drivers/acpi/acpica/exoparg2.c index 6fac5e0a698a..b8944ebb1081 100644 --- a/drivers/acpi/acpica/exoparg2.c +++ b/drivers/acpi/acpica/exoparg2.c @@ -337,8 +337,8 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state) * Copy the raw buffer data with no transform. * (NULL terminated already) */ - ACPI_MEMCPY(return_desc->string.pointer, - operand[0]->buffer.pointer, length); + memcpy(return_desc->string.pointer, + operand[0]->buffer.pointer, length); break; case AML_CONCAT_RES_OP: diff --git a/drivers/acpi/acpica/exoparg3.c b/drivers/acpi/acpica/exoparg3.c index 1c64a988cbee..fa100b3b92ee 100644 --- a/drivers/acpi/acpica/exoparg3.c +++ b/drivers/acpi/acpica/exoparg3.c @@ -237,8 +237,8 @@ acpi_status acpi_ex_opcode_3A_1T_1R(struct acpi_walk_state *walk_state) /* We have a buffer, copy the portion requested */ - ACPI_MEMCPY(buffer, operand[0]->string.pointer + index, - length); + memcpy(buffer, operand[0]->string.pointer + index, + length); } /* Set the length of the new String/Buffer */ diff --git a/drivers/acpi/acpica/exregion.c b/drivers/acpi/acpica/exregion.c index f6c2f5499935..b4a5e44c00dd 100644 --- a/drivers/acpi/acpica/exregion.c +++ b/drivers/acpi/acpica/exregion.c @@ -517,15 +517,14 @@ acpi_ex_data_table_space_handler(u32 function, switch (function) { case ACPI_READ: - ACPI_MEMCPY(ACPI_CAST_PTR(char, value), - ACPI_PHYSADDR_TO_PTR(address), - ACPI_DIV_8(bit_width)); + memcpy(ACPI_CAST_PTR(char, value), + ACPI_PHYSADDR_TO_PTR(address), ACPI_DIV_8(bit_width)); break; case ACPI_WRITE: - ACPI_MEMCPY(ACPI_PHYSADDR_TO_PTR(address), - ACPI_CAST_PTR(char, value), ACPI_DIV_8(bit_width)); + memcpy(ACPI_PHYSADDR_TO_PTR(address), + ACPI_CAST_PTR(char, value), ACPI_DIV_8(bit_width)); break; default: diff --git a/drivers/acpi/acpica/exstorob.c b/drivers/acpi/acpica/exstorob.c index 6fa3c8d8fc5f..e1d4f4d51b97 100644 --- a/drivers/acpi/acpica/exstorob.c +++ b/drivers/acpi/acpica/exstorob.c @@ -100,9 +100,9 @@ acpi_ex_store_buffer_to_buffer(union acpi_operand_object *source_desc, /* Clear existing buffer and copy in the new one */ - ACPI_MEMSET(target_desc->buffer.pointer, 0, - target_desc->buffer.length); - ACPI_MEMCPY(target_desc->buffer.pointer, buffer, length); + memset(target_desc->buffer.pointer, 0, + target_desc->buffer.length); + memcpy(target_desc->buffer.pointer, buffer, length); #ifdef ACPI_OBSOLETE_BEHAVIOR /* @@ -129,8 +129,8 @@ acpi_ex_store_buffer_to_buffer(union acpi_operand_object *source_desc, } else { /* Truncate the source, copy only what will fit */ - ACPI_MEMCPY(target_desc->buffer.pointer, buffer, - target_desc->buffer.length); + memcpy(target_desc->buffer.pointer, buffer, + target_desc->buffer.length); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Truncating source buffer from %X to %X\n", @@ -187,9 +187,9 @@ acpi_ex_store_string_to_string(union acpi_operand_object *source_desc, * String will fit in existing non-static buffer. * Clear old string and copy in the new one */ - ACPI_MEMSET(target_desc->string.pointer, 0, - (acpi_size) target_desc->string.length + 1); - ACPI_MEMCPY(target_desc->string.pointer, buffer, length); + memset(target_desc->string.pointer, 0, + (acpi_size) target_desc->string.length + 1); + memcpy(target_desc->string.pointer, buffer, length); } else { /* * Free the current buffer, then allocate a new buffer @@ -210,7 +210,7 @@ acpi_ex_store_string_to_string(union acpi_operand_object *source_desc, } target_desc->common.flags &= ~AOPOBJ_STATIC_POINTER; - ACPI_MEMCPY(target_desc->string.pointer, buffer, length); + memcpy(target_desc->string.pointer, buffer, length); } /* Set the new target length */ diff --git a/drivers/acpi/acpica/nsaccess.c b/drivers/acpi/acpica/nsaccess.c index 19ad0b5993d5..c687b9979fb2 100644 --- a/drivers/acpi/acpica/nsaccess.c +++ b/drivers/acpi/acpica/nsaccess.c @@ -102,7 +102,7 @@ acpi_status acpi_ns_root_initialize(void) /* _OSI is optional for now, will be permanent later */ - if (!ACPI_STRCMP(init_val->name, "_OSI") + if (!strcmp(init_val->name, "_OSI") && !acpi_gbl_create_osi_method) { continue; } @@ -180,7 +180,7 @@ acpi_status acpi_ns_root_initialize(void) /* Build an object around the static string */ - obj_desc->string.length = (u32)ACPI_STRLEN(val); + obj_desc->string.length = (u32)strlen(val); obj_desc->string.pointer = val; obj_desc->common.flags |= AOPOBJ_STATIC_POINTER; break; @@ -203,7 +203,7 @@ acpi_status acpi_ns_root_initialize(void) /* Special case for ACPI Global Lock */ - if (ACPI_STRCMP(init_val->name, "_GL_") == 0) { + if (strcmp(init_val->name, "_GL_") == 0) { acpi_gbl_global_lock_mutex = obj_desc; /* Create additional counting semaphore for global lock */ diff --git a/drivers/acpi/acpica/nsconvert.c b/drivers/acpi/acpica/nsconvert.c index 1a8b39c8d969..da55a1c60da1 100644 --- a/drivers/acpi/acpica/nsconvert.c +++ b/drivers/acpi/acpica/nsconvert.c @@ -187,8 +187,8 @@ acpi_ns_convert_to_string(union acpi_operand_object *original_object, * Copy the raw buffer data with no transform. String is already NULL * terminated at Length+1. */ - ACPI_MEMCPY(new_object->string.pointer, - original_object->buffer.pointer, length); + memcpy(new_object->string.pointer, + original_object->buffer.pointer, length); break; default: @@ -251,9 +251,9 @@ acpi_ns_convert_to_buffer(union acpi_operand_object *original_object, return (AE_NO_MEMORY); } - ACPI_MEMCPY(new_object->buffer.pointer, - original_object->string.pointer, - original_object->string.length); + memcpy(new_object->buffer.pointer, + original_object->string.pointer, + original_object->string.length); break; case ACPI_TYPE_PACKAGE: diff --git a/drivers/acpi/acpica/nsdump.c b/drivers/acpi/acpica/nsdump.c index d259393505fa..0f1daba640e7 100644 --- a/drivers/acpi/acpica/nsdump.c +++ b/drivers/acpi/acpica/nsdump.c @@ -101,7 +101,7 @@ void acpi_ns_print_pathname(u32 num_segments, char *pathname) while (num_segments) { for (i = 0; i < 4; i++) { - ACPI_IS_PRINT(pathname[i]) ? + isprint((int)pathname[i]) ? acpi_os_printf("%c", pathname[i]) : acpi_os_printf("?"); } diff --git a/drivers/acpi/acpica/nseval.c b/drivers/acpi/acpica/nseval.c index 7bcc68f57afa..a725d88b036b 100644 --- a/drivers/acpi/acpica/nseval.c +++ b/drivers/acpi/acpica/nseval.c @@ -440,7 +440,7 @@ acpi_ns_exec_module_code(union acpi_operand_object *method_obj, /* Initialize the evaluation information block */ - ACPI_MEMSET(info, 0, sizeof(struct acpi_evaluate_info)); + memset(info, 0, sizeof(struct acpi_evaluate_info)); info->prefix_node = parent_node; /* diff --git a/drivers/acpi/acpica/nsinit.c b/drivers/acpi/acpica/nsinit.c index 4a85c4517988..b744a53618eb 100644 --- a/drivers/acpi/acpica/nsinit.c +++ b/drivers/acpi/acpica/nsinit.c @@ -90,7 +90,7 @@ acpi_status acpi_ns_initialize_objects(void) /* Set all init info to zero */ - ACPI_MEMSET(&info, 0, sizeof(struct acpi_init_walk_info)); + memset(&info, 0, sizeof(struct acpi_init_walk_info)); /* Walk entire namespace from the supplied root */ @@ -566,7 +566,7 @@ acpi_ns_init_one_device(acpi_handle obj_handle, ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname (ACPI_TYPE_METHOD, device_node, METHOD_NAME__INI)); - ACPI_MEMSET(info, 0, sizeof(struct acpi_evaluate_info)); + memset(info, 0, sizeof(struct acpi_evaluate_info)); info->prefix_node = device_node; info->relative_pathname = METHOD_NAME__INI; info->parameters = NULL; diff --git a/drivers/acpi/acpica/nsrepair2.c b/drivers/acpi/acpica/nsrepair2.c index c30672d23878..0515a70f42a4 100644 --- a/drivers/acpi/acpica/nsrepair2.c +++ b/drivers/acpi/acpica/nsrepair2.c @@ -580,7 +580,7 @@ acpi_ns_repair_HID(struct acpi_evaluate_info *info, * # is a hex digit. */ for (dest = new_string->string.pointer; *source; dest++, source++) { - *dest = (char)ACPI_TOUPPER(*source); + *dest = (char)toupper((int)*source); } acpi_ut_remove_reference(return_object); diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c index 6ad02008c0c2..8d8104b8bd28 100644 --- a/drivers/acpi/acpica/nsutils.c +++ b/drivers/acpi/acpica/nsutils.c @@ -292,8 +292,7 @@ acpi_status acpi_ns_build_internal_name(struct acpi_namestring_info *info) } else { /* Convert the character to uppercase and save it */ - result[i] = - (char)ACPI_TOUPPER((int)*external_name); + result[i] = (char)toupper((int)*external_name); external_name++; } } diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c index b6030a2deee1..6ee1e52b903d 100644 --- a/drivers/acpi/acpica/nsxfeval.c +++ b/drivers/acpi/acpica/nsxfeval.c @@ -696,7 +696,7 @@ acpi_ns_get_device_callback(acpi_handle obj_handle, return (AE_CTRL_DEPTH); } - no_match = ACPI_STRCMP(hid->string, info->hid); + no_match = strcmp(hid->string, info->hid); ACPI_FREE(hid); if (no_match) { @@ -715,8 +715,7 @@ acpi_ns_get_device_callback(acpi_handle obj_handle, found = FALSE; for (i = 0; i < cid->count; i++) { - if (ACPI_STRCMP(cid->ids[i].string, info->hid) - == 0) { + if (strcmp(cid->ids[i].string, info->hid) == 0) { /* Found a matching CID */ diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index dc0836a9cf17..9ff643b9553f 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c @@ -114,7 +114,7 @@ acpi_get_handle(acpi_handle parent, /* Special case for root-only, since we can't search for it */ - if (!ACPI_STRCMP(pathname, ACPI_NS_ROOT_PATH)) { + if (!strcmp(pathname, ACPI_NS_ROOT_PATH)) { *ret_handle = ACPI_CAST_PTR(acpi_handle, acpi_gbl_root_node); return (AE_OK); @@ -242,7 +242,7 @@ static char *acpi_ns_copy_device_id(struct acpi_pnp_device_id *dest, /* Copy actual string and return a pointer to the next string area */ - ACPI_MEMCPY(string_area, source->string, source->length); + memcpy(string_area, source->string, source->length); return (string_area + source->length); } @@ -637,7 +637,7 @@ acpi_status acpi_install_method(u8 *buffer) /* Copy the method AML to the local buffer */ - ACPI_MEMCPY(aml_buffer, aml_start, aml_length); + memcpy(aml_buffer, aml_start, aml_length); /* Initialize the method object with the new method's information */ diff --git a/drivers/acpi/acpica/psutils.c b/drivers/acpi/acpica/psutils.c index 960505ab409a..32440912023a 100644 --- a/drivers/acpi/acpica/psutils.c +++ b/drivers/acpi/acpica/psutils.c @@ -93,10 +93,9 @@ void acpi_ps_init_op(union acpi_parse_object *op, u16 opcode) op->common.descriptor_type = ACPI_DESC_TYPE_PARSER; op->common.aml_opcode = opcode; - ACPI_DISASM_ONLY_MEMBERS(ACPI_STRNCPY(op->common.aml_op_name, - (acpi_ps_get_opcode_info - (opcode))->name, - sizeof(op->common.aml_op_name))); + ACPI_DISASM_ONLY_MEMBERS(strncpy(op->common.aml_op_name, + (acpi_ps_get_opcode_info(opcode))-> + name, sizeof(op->common.aml_op_name))); } /******************************************************************************* diff --git a/drivers/acpi/acpica/rscreate.c b/drivers/acpi/acpica/rscreate.c index f30f35e6ff2a..3fa829e96c2a 100644 --- a/drivers/acpi/acpica/rscreate.c +++ b/drivers/acpi/acpica/rscreate.c @@ -353,13 +353,13 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object, /* +1 to include null terminator */ user_prt->length += - (u32)ACPI_STRLEN(user_prt->source) + 1; + (u32)strlen(user_prt->source) + 1; break; case ACPI_TYPE_STRING: - ACPI_STRCPY(user_prt->source, - obj_desc->string.pointer); + strcpy(user_prt->source, + obj_desc->string.pointer); /* * Add to the Length field the length of the string diff --git a/drivers/acpi/acpica/rsmisc.c b/drivers/acpi/acpica/rsmisc.c index 1fe49d223663..ac37852e0821 100644 --- a/drivers/acpi/acpica/rsmisc.c +++ b/drivers/acpi/acpica/rsmisc.c @@ -119,7 +119,7 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource, /* * Get the resource type and the initial (minimum) length */ - ACPI_MEMSET(resource, 0, INIT_RESOURCE_LENGTH(info)); + memset(resource, 0, INIT_RESOURCE_LENGTH(info)); resource->type = INIT_RESOURCE_TYPE(info); resource->length = INIT_RESOURCE_LENGTH(info); break; @@ -324,13 +324,13 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource, case ACPI_RSC_SET8: - ACPI_MEMSET(destination, info->aml_offset, info->value); + memset(destination, info->aml_offset, info->value); break; case ACPI_RSC_DATA8: target = ACPI_ADD_PTR(char, resource, info->value); - ACPI_MEMCPY(destination, source, ACPI_GET16(target)); + memcpy(destination, source, ACPI_GET16(target)); break; case ACPI_RSC_ADDRESS: @@ -502,7 +502,7 @@ acpi_rs_convert_resource_to_aml(struct acpi_resource *resource, switch (info->opcode) { case ACPI_RSC_INITSET: - ACPI_MEMSET(aml, 0, INIT_RESOURCE_LENGTH(info)); + memset(aml, 0, INIT_RESOURCE_LENGTH(info)); aml_length = INIT_RESOURCE_LENGTH(info); acpi_rs_set_resource_header(INIT_RESOURCE_TYPE(info), aml_length, aml); diff --git a/drivers/acpi/acpica/rsutils.c b/drivers/acpi/acpica/rsutils.c index 90417de38dab..52b024df0052 100644 --- a/drivers/acpi/acpica/rsutils.c +++ b/drivers/acpi/acpica/rsutils.c @@ -148,7 +148,7 @@ acpi_rs_move_data(void *destination, void *source, u16 item_count, u8 move_type) case ACPI_RSC_MOVE_SERIAL_VEN: case ACPI_RSC_MOVE_SERIAL_RES: - ACPI_MEMCPY(destination, source, item_count); + memcpy(destination, source, item_count); return; /* @@ -364,12 +364,11 @@ acpi_rs_get_resource_source(acpi_rs_length resource_length, * Zero the entire area of the buffer. */ total_length = - (u32) - ACPI_STRLEN(ACPI_CAST_PTR(char, &aml_resource_source[1])) + + (u32)strlen(ACPI_CAST_PTR(char, &aml_resource_source[1])) + 1; total_length = (u32)ACPI_ROUND_UP_TO_NATIVE_WORD(total_length); - ACPI_MEMSET(resource_source->string_ptr, 0, total_length); + memset(resource_source->string_ptr, 0, total_length); /* Copy the resource_source string to the destination */ @@ -432,8 +431,8 @@ acpi_rs_set_resource_source(union aml_resource * aml, /* Copy the resource_source string */ - ACPI_STRCPY(ACPI_CAST_PTR(char, &aml_resource_source[1]), - resource_source->string_ptr); + strcpy(ACPI_CAST_PTR(char, &aml_resource_source[1]), + resource_source->string_ptr); /* * Add the length of the string (+ 1 for null terminator) to the diff --git a/drivers/acpi/acpica/rsxface.c b/drivers/acpi/acpica/rsxface.c index 8e6276df0226..de51f836ef68 100644 --- a/drivers/acpi/acpica/rsxface.c +++ b/drivers/acpi/acpica/rsxface.c @@ -398,8 +398,8 @@ acpi_resource_to_address64(struct acpi_resource *resource, /* Simple copy for 64 bit source */ - ACPI_MEMCPY(out, &resource->data, - sizeof(struct acpi_resource_address64)); + memcpy(out, &resource->data, + sizeof(struct acpi_resource_address64)); break; default: @@ -499,7 +499,7 @@ acpi_rs_match_vendor_resource(struct acpi_resource *resource, void *context) */ if ((vendor->byte_length < (ACPI_UUID_LENGTH + 1)) || (vendor->uuid_subtype != info->uuid->subtype) || - (ACPI_MEMCMP(vendor->uuid, info->uuid->data, ACPI_UUID_LENGTH))) { + (memcmp(vendor->uuid, info->uuid->data, ACPI_UUID_LENGTH))) { return (AE_OK); } @@ -513,7 +513,7 @@ acpi_rs_match_vendor_resource(struct acpi_resource *resource, void *context) /* Found the correct resource, copy and return it */ - ACPI_MEMCPY(buffer->pointer, resource, resource->length); + memcpy(buffer->pointer, resource, resource->length); buffer->length = resource->length; /* Found the desired descriptor, terminate resource walk */ diff --git a/drivers/acpi/acpica/tbdata.c b/drivers/acpi/acpica/tbdata.c index d7f8386455bd..5c9d5abf1588 100644 --- a/drivers/acpi/acpica/tbdata.c +++ b/drivers/acpi/acpica/tbdata.c @@ -73,7 +73,7 @@ acpi_tb_init_table_descriptor(struct acpi_table_desc *table_desc, * Initialize the table descriptor. Set the pointer to NULL, since the * table is not fully mapped at this time. */ - ACPI_MEMSET(table_desc, 0, sizeof(struct acpi_table_desc)); + memset(table_desc, 0, sizeof(struct acpi_table_desc)); table_desc->address = address; table_desc->length = table->length; table_desc->flags = flags; @@ -465,9 +465,9 @@ acpi_status acpi_tb_resize_root_table_list(void) /* Copy and free the previous table array */ if (acpi_gbl_root_table_list.tables) { - ACPI_MEMCPY(tables, acpi_gbl_root_table_list.tables, - (acpi_size) table_count * - sizeof(struct acpi_table_desc)); + memcpy(tables, acpi_gbl_root_table_list.tables, + (acpi_size) table_count * + sizeof(struct acpi_table_desc)); if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) { ACPI_FREE(acpi_gbl_root_table_list.tables); diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c index 05be59c772c7..6253001b6375 100644 --- a/drivers/acpi/acpica/tbfadt.c +++ b/drivers/acpi/acpica/tbfadt.c @@ -398,12 +398,12 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length) /* Clear the entire local FADT */ - ACPI_MEMSET(&acpi_gbl_FADT, 0, sizeof(struct acpi_table_fadt)); + memset(&acpi_gbl_FADT, 0, sizeof(struct acpi_table_fadt)); /* Copy the original FADT, up to sizeof (struct acpi_table_fadt) */ - ACPI_MEMCPY(&acpi_gbl_FADT, table, - ACPI_MIN(length, sizeof(struct acpi_table_fadt))); + memcpy(&acpi_gbl_FADT, table, + ACPI_MIN(length, sizeof(struct acpi_table_fadt))); /* Take a copy of the Hardware Reduced flag */ diff --git a/drivers/acpi/acpica/tbfind.c b/drivers/acpi/acpica/tbfind.c index 0b879fcfef67..119c84ad9833 100644 --- a/drivers/acpi/acpica/tbfind.c +++ b/drivers/acpi/acpica/tbfind.c @@ -76,16 +76,16 @@ acpi_tb_find_table(char *signature, /* Normalize the input strings */ - ACPI_MEMSET(&header, 0, sizeof(struct acpi_table_header)); + memset(&header, 0, sizeof(struct acpi_table_header)); ACPI_MOVE_NAME(header.signature, signature); - ACPI_STRNCPY(header.oem_id, oem_id, ACPI_OEM_ID_SIZE); - ACPI_STRNCPY(header.oem_table_id, oem_table_id, ACPI_OEM_TABLE_ID_SIZE); + strncpy(header.oem_id, oem_id, ACPI_OEM_ID_SIZE); + strncpy(header.oem_table_id, oem_table_id, ACPI_OEM_TABLE_ID_SIZE); /* Search for the table */ for (i = 0; i < acpi_gbl_root_table_list.current_table_count; ++i) { - if (ACPI_MEMCMP(&(acpi_gbl_root_table_list.tables[i].signature), - header.signature, ACPI_NAME_SIZE)) { + if (memcmp(&(acpi_gbl_root_table_list.tables[i].signature), + header.signature, ACPI_NAME_SIZE)) { /* Not the requested table */ @@ -112,21 +112,20 @@ acpi_tb_find_table(char *signature, /* Check for table match on all IDs */ - if (!ACPI_MEMCMP + if (!memcmp (acpi_gbl_root_table_list.tables[i].pointer->signature, header.signature, ACPI_NAME_SIZE) && (!oem_id[0] || - !ACPI_MEMCMP + !memcmp (acpi_gbl_root_table_list. tables[i].pointer-> oem_id, header.oem_id, ACPI_OEM_ID_SIZE)) && (!oem_table_id[0] - || !ACPI_MEMCMP(acpi_gbl_root_table_list.tables[i]. - pointer->oem_table_id, - header.oem_table_id, - ACPI_OEM_TABLE_ID_SIZE))) { + || !memcmp(acpi_gbl_root_table_list.tables[i].pointer-> + oem_table_id, header.oem_table_id, + ACPI_OEM_TABLE_ID_SIZE))) { *table_index = i; ACPI_DEBUG_PRINT((ACPI_DB_TABLES, diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index 008a251780f4..15ea98e0068d 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -87,8 +87,8 @@ acpi_tb_compare_tables(struct acpi_table_desc *table_desc, u32 table_index) * not just the header. */ is_identical = (u8)((table_desc->length != table_length || - ACPI_MEMCMP(table_desc->pointer, table, - table_length)) ? FALSE : TRUE); + memcmp(table_desc->pointer, table, table_length)) ? + FALSE : TRUE); /* Release the acquired table */ @@ -289,8 +289,7 @@ acpi_tb_install_standard_table(acpi_physical_address address, if ((new_table_desc.signature.ascii[0] != 0x00) && (!ACPI_COMPARE_NAME (&new_table_desc.signature, ACPI_SIG_SSDT)) - && (ACPI_STRNCMP(new_table_desc.signature.ascii, "OEM", 3))) - { + && (strncmp(new_table_desc.signature.ascii, "OEM", 3))) { ACPI_BIOS_ERROR((AE_INFO, "Table has invalid signature [%4.4s] (0x%8.8X), " "must be SSDT or OEMx", diff --git a/drivers/acpi/acpica/tbprint.c b/drivers/acpi/acpica/tbprint.c index 77ba5c71c6e7..709d5112fc16 100644 --- a/drivers/acpi/acpica/tbprint.c +++ b/drivers/acpi/acpica/tbprint.c @@ -73,7 +73,7 @@ static void acpi_tb_fix_string(char *string, acpi_size length) { while (length && *string) { - if (!ACPI_IS_PRINT(*string)) { + if (!isprint((int)*string)) { *string = '?'; } string++; @@ -100,7 +100,7 @@ acpi_tb_cleanup_table_header(struct acpi_table_header *out_header, struct acpi_table_header *header) { - ACPI_MEMCPY(out_header, header, sizeof(struct acpi_table_header)); + memcpy(out_header, header, sizeof(struct acpi_table_header)); acpi_tb_fix_string(out_header->signature, ACPI_NAME_SIZE); acpi_tb_fix_string(out_header->oem_id, ACPI_OEM_ID_SIZE); @@ -138,9 +138,9 @@ acpi_tb_print_table_header(acpi_physical_address address, /* RSDP has no common fields */ - ACPI_MEMCPY(local_header.oem_id, - ACPI_CAST_PTR(struct acpi_table_rsdp, - header)->oem_id, ACPI_OEM_ID_SIZE); + memcpy(local_header.oem_id, + ACPI_CAST_PTR(struct acpi_table_rsdp, header)->oem_id, + ACPI_OEM_ID_SIZE); acpi_tb_fix_string(local_header.oem_id, ACPI_OEM_ID_SIZE); ACPI_INFO((AE_INFO, "RSDP 0x%8.8X%8.8X %06X (v%.2d %-6.6s)", diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index 2bb6a117c840..568ac0e4a3c6 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -188,7 +188,7 @@ struct acpi_table_header *acpi_tb_copy_dsdt(u32 table_index) return (NULL); } - ACPI_MEMCPY(new_table, table_desc->pointer, table_desc->length); + memcpy(new_table, table_desc->pointer, table_desc->length); acpi_tb_uninstall_table(table_desc); acpi_tb_init_table_descriptor(&acpi_gbl_root_table_list. diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c index 54b9f7957ff1..5559e2c70b15 100644 --- a/drivers/acpi/acpica/tbxface.c +++ b/drivers/acpi/acpica/tbxface.c @@ -119,9 +119,9 @@ acpi_initialize_tables(struct acpi_table_desc * initial_table_array, } else { /* Root Table Array has been statically allocated by the host */ - ACPI_MEMSET(initial_table_array, 0, - (acpi_size) initial_table_count * - sizeof(struct acpi_table_desc)); + memset(initial_table_array, 0, + (acpi_size) initial_table_count * + sizeof(struct acpi_table_desc)); acpi_gbl_root_table_list.tables = initial_table_array; acpi_gbl_root_table_list.max_table_count = initial_table_count; @@ -243,8 +243,8 @@ acpi_get_table_header(char *signature, return (AE_NO_MEMORY); } - ACPI_MEMCPY(out_table_header, header, - sizeof(struct acpi_table_header)); + memcpy(out_table_header, header, + sizeof(struct acpi_table_header)); acpi_os_unmap_memory(header, sizeof(struct acpi_table_header)); @@ -252,9 +252,9 @@ acpi_get_table_header(char *signature, return (AE_NOT_FOUND); } } else { - ACPI_MEMCPY(out_table_header, - acpi_gbl_root_table_list.tables[i].pointer, - sizeof(struct acpi_table_header)); + memcpy(out_table_header, + acpi_gbl_root_table_list.tables[i].pointer, + sizeof(struct acpi_table_header)); } return (AE_OK); } diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c index cf56e18cdc64..9682d40ca6ff 100644 --- a/drivers/acpi/acpica/tbxfload.c +++ b/drivers/acpi/acpica/tbxfload.c @@ -150,8 +150,8 @@ static acpi_status acpi_tb_load_namespace(void) * Save the original DSDT header for detection of table corruption * and/or replacement of the DSDT from outside the OS. */ - ACPI_MEMCPY(&acpi_gbl_original_dsdt_header, acpi_gbl_DSDT, - sizeof(struct acpi_table_header)); + memcpy(&acpi_gbl_original_dsdt_header, acpi_gbl_DSDT, + sizeof(struct acpi_table_header)); (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); diff --git a/drivers/acpi/acpica/utalloc.c b/drivers/acpi/acpica/utalloc.c index 61d8f6d186d1..7a4101f0685e 100644 --- a/drivers/acpi/acpica/utalloc.c +++ b/drivers/acpi/acpica/utalloc.c @@ -73,7 +73,7 @@ void *acpi_os_allocate_zeroed(acpi_size size) /* Clear the memory block */ - ACPI_MEMSET(allocation, 0, size); + memset(allocation, 0, size); } return (allocation); @@ -181,7 +181,7 @@ acpi_status acpi_ut_delete_caches(void) char buffer[7]; if (acpi_gbl_display_final_mem_stats) { - ACPI_STRCPY(buffer, "MEMORY"); + strcpy(buffer, "MEMORY"); (void)acpi_db_display_statistics(buffer); } #endif @@ -337,6 +337,6 @@ acpi_ut_initialize_buffer(struct acpi_buffer * buffer, /* Have a valid buffer, clear it */ - ACPI_MEMSET(buffer->pointer, 0, required_length); + memset(buffer->pointer, 0, required_length); return (AE_OK); } diff --git a/drivers/acpi/acpica/utbuffer.c b/drivers/acpi/acpica/utbuffer.c index a8c39643e618..01c8709ca586 100644 --- a/drivers/acpi/acpica/utbuffer.c +++ b/drivers/acpi/acpica/utbuffer.c @@ -159,7 +159,7 @@ void acpi_ut_dump_buffer(u8 *buffer, u32 count, u32 display, u32 base_offset) } buf_char = buffer[(acpi_size) i + j]; - if (ACPI_IS_PRINT(buf_char)) { + if (isprint(buf_char)) { acpi_os_printf("%c", buf_char); } else { acpi_os_printf("."); @@ -319,7 +319,7 @@ acpi_ut_dump_buffer_to_file(ACPI_FILE file, } buf_char = buffer[(acpi_size) i + j]; - if (ACPI_IS_PRINT(buf_char)) { + if (isprint(buf_char)) { acpi_ut_file_printf(file, "%c", buf_char); } else { acpi_ut_file_printf(file, "."); diff --git a/drivers/acpi/acpica/utcache.c b/drivers/acpi/acpica/utcache.c index eacc5eee362e..0d21fbd99363 100644 --- a/drivers/acpi/acpica/utcache.c +++ b/drivers/acpi/acpica/utcache.c @@ -84,7 +84,7 @@ acpi_os_create_cache(char *cache_name, /* Populate the cache object and return it */ - ACPI_MEMSET(cache, 0, sizeof(struct acpi_memory_list)); + memset(cache, 0, sizeof(struct acpi_memory_list)); cache->list_name = cache_name; cache->object_size = object_size; cache->max_depth = max_depth; @@ -212,7 +212,7 @@ acpi_os_release_object(struct acpi_memory_list * cache, void *object) /* Mark the object as cached */ - ACPI_MEMSET(object, 0xCA, cache->object_size); + memset(object, 0xCA, cache->object_size); ACPI_SET_DESCRIPTOR_TYPE(object, ACPI_DESC_TYPE_CACHED); /* Put the object at the head of the cache list */ @@ -281,7 +281,7 @@ void *acpi_os_acquire_object(struct acpi_memory_list *cache) /* Clear (zero) the previously used Object */ - ACPI_MEMSET(object, 0, cache->object_size); + memset(object, 0, cache->object_size); } else { /* The cache is empty, create a new object */ diff --git a/drivers/acpi/acpica/utcopy.c b/drivers/acpi/acpica/utcopy.c index c37ec5035f4c..257221d452c8 100644 --- a/drivers/acpi/acpica/utcopy.c +++ b/drivers/acpi/acpica/utcopy.c @@ -129,7 +129,7 @@ acpi_ut_copy_isimple_to_esimple(union acpi_operand_object *internal_object, /* Always clear the external object */ - ACPI_MEMSET(external_object, 0, sizeof(union acpi_object)); + memset(external_object, 0, sizeof(union acpi_object)); /* * In general, the external object will be the same type as @@ -149,9 +149,9 @@ acpi_ut_copy_isimple_to_esimple(union acpi_operand_object *internal_object, string. length + 1); - ACPI_MEMCPY((void *)data_space, - (void *)internal_object->string.pointer, - (acpi_size) internal_object->string.length + 1); + memcpy((void *)data_space, + (void *)internal_object->string.pointer, + (acpi_size) internal_object->string.length + 1); break; case ACPI_TYPE_BUFFER: @@ -162,9 +162,9 @@ acpi_ut_copy_isimple_to_esimple(union acpi_operand_object *internal_object, ACPI_ROUND_UP_TO_NATIVE_WORD(internal_object->string. length); - ACPI_MEMCPY((void *)data_space, - (void *)internal_object->buffer.pointer, - internal_object->buffer.length); + memcpy((void *)data_space, + (void *)internal_object->buffer.pointer, + internal_object->buffer.length); break; case ACPI_TYPE_INTEGER: @@ -502,9 +502,9 @@ acpi_ut_copy_esimple_to_isimple(union acpi_object *external_object, goto error_exit; } - ACPI_MEMCPY(internal_object->string.pointer, - external_object->string.pointer, - external_object->string.length); + memcpy(internal_object->string.pointer, + external_object->string.pointer, + external_object->string.length); internal_object->string.length = external_object->string.length; break; @@ -517,9 +517,9 @@ acpi_ut_copy_esimple_to_isimple(union acpi_object *external_object, goto error_exit; } - ACPI_MEMCPY(internal_object->buffer.pointer, - external_object->buffer.pointer, - external_object->buffer.length); + memcpy(internal_object->buffer.pointer, + external_object->buffer.pointer, + external_object->buffer.length); internal_object->buffer.length = external_object->buffer.length; @@ -694,8 +694,8 @@ acpi_ut_copy_simple_object(union acpi_operand_object *source_desc, copy_size = sizeof(struct acpi_namespace_node); } - ACPI_MEMCPY(ACPI_CAST_PTR(char, dest_desc), - ACPI_CAST_PTR(char, source_desc), copy_size); + memcpy(ACPI_CAST_PTR(char, dest_desc), + ACPI_CAST_PTR(char, source_desc), copy_size); /* Restore the saved fields */ @@ -725,9 +725,9 @@ acpi_ut_copy_simple_object(union acpi_operand_object *source_desc, /* Copy the actual buffer data */ - ACPI_MEMCPY(dest_desc->buffer.pointer, - source_desc->buffer.pointer, - source_desc->buffer.length); + memcpy(dest_desc->buffer.pointer, + source_desc->buffer.pointer, + source_desc->buffer.length); } break; @@ -747,9 +747,9 @@ acpi_ut_copy_simple_object(union acpi_operand_object *source_desc, /* Copy the actual string data */ - ACPI_MEMCPY(dest_desc->string.pointer, - source_desc->string.pointer, - (acpi_size) source_desc->string.length + 1); + memcpy(dest_desc->string.pointer, + source_desc->string.pointer, + (acpi_size) source_desc->string.length + 1); } break; diff --git a/drivers/acpi/acpica/utids.c b/drivers/acpi/acpica/utids.c index 3afe07f19b9f..7956df1e263c 100644 --- a/drivers/acpi/acpica/utids.c +++ b/drivers/acpi/acpica/utids.c @@ -111,7 +111,7 @@ acpi_ut_execute_HID(struct acpi_namespace_node *device_node, if (obj_desc->common.type == ACPI_TYPE_INTEGER) { acpi_ex_eisa_id_to_string(hid->string, obj_desc->integer.value); } else { - ACPI_STRCPY(hid->string, obj_desc->string.pointer); + strcpy(hid->string, obj_desc->string.pointer); } hid->length = length; @@ -180,7 +180,7 @@ acpi_ut_execute_SUB(struct acpi_namespace_node *device_node, /* Simply copy existing string */ - ACPI_STRCPY(sub->string, obj_desc->string.pointer); + strcpy(sub->string, obj_desc->string.pointer); sub->length = length; *return_id = sub; @@ -256,7 +256,7 @@ acpi_ut_execute_UID(struct acpi_namespace_node *device_node, if (obj_desc->common.type == ACPI_TYPE_INTEGER) { acpi_ex_integer_to_string(uid->string, obj_desc->integer.value); } else { - ACPI_STRCPY(uid->string, obj_desc->string.pointer); + strcpy(uid->string, obj_desc->string.pointer); } uid->length = length; @@ -393,8 +393,7 @@ acpi_ut_execute_CID(struct acpi_namespace_node *device_node, /* Copy the String CID from the returned object */ - ACPI_STRCPY(next_id_string, - cid_objects[i]->string.pointer); + strcpy(next_id_string, cid_objects[i]->string.pointer); length = cid_objects[i]->string.length + 1; } diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c index 28099e230008..71b66537f826 100644 --- a/drivers/acpi/acpica/utmisc.c +++ b/drivers/acpi/acpica/utmisc.c @@ -66,9 +66,9 @@ u8 acpi_ut_is_pci_root_bridge(char *id) * Check if this is a PCI root bridge. * ACPI 3.0+: check for a PCI Express root also. */ - if (!(ACPI_STRCMP(id, - PCI_ROOT_HID_STRING)) || - !(ACPI_STRCMP(id, PCI_EXPRESS_ROOT_HID_STRING))) { + if (!(strcmp(id, + PCI_ROOT_HID_STRING)) || + !(strcmp(id, PCI_EXPRESS_ROOT_HID_STRING))) { return (TRUE); } diff --git a/drivers/acpi/acpica/utosi.c b/drivers/acpi/acpica/utosi.c index 44035abdbf29..8f3d203aed79 100644 --- a/drivers/acpi/acpica/utosi.c +++ b/drivers/acpi/acpica/utosi.c @@ -232,8 +232,7 @@ acpi_status acpi_ut_install_interface(acpi_string interface_name) return (AE_NO_MEMORY); } - interface_info->name = - ACPI_ALLOCATE_ZEROED(ACPI_STRLEN(interface_name) + 1); + interface_info->name = ACPI_ALLOCATE_ZEROED(strlen(interface_name) + 1); if (!interface_info->name) { ACPI_FREE(interface_info); return (AE_NO_MEMORY); @@ -241,7 +240,7 @@ acpi_status acpi_ut_install_interface(acpi_string interface_name) /* Initialize new info and insert at the head of the global list */ - ACPI_STRCPY(interface_info->name, interface_name); + strcpy(interface_info->name, interface_name); interface_info->flags = ACPI_OSI_DYNAMIC; interface_info->next = acpi_gbl_supported_interfaces; @@ -269,7 +268,7 @@ acpi_status acpi_ut_remove_interface(acpi_string interface_name) previous_interface = next_interface = acpi_gbl_supported_interfaces; while (next_interface) { - if (!ACPI_STRCMP(interface_name, next_interface->name)) { + if (!strcmp(interface_name, next_interface->name)) { /* Found: name is in either the static list or was added at runtime */ @@ -373,7 +372,7 @@ struct acpi_interface_info *acpi_ut_get_interface(acpi_string interface_name) next_interface = acpi_gbl_supported_interfaces; while (next_interface) { - if (!ACPI_STRCMP(interface_name, next_interface->name)) { + if (!strcmp(interface_name, next_interface->name)) { return (next_interface); } diff --git a/drivers/acpi/acpica/utpredef.c b/drivers/acpi/acpica/utpredef.c index 29e449935a82..97898ed71b4b 100644 --- a/drivers/acpi/acpica/utpredef.c +++ b/drivers/acpi/acpica/utpredef.c @@ -148,7 +148,7 @@ void acpi_ut_get_expected_return_types(char *buffer, u32 expected_btypes) u32 j; if (!expected_btypes) { - ACPI_STRCPY(buffer, "NONE"); + strcpy(buffer, "NONE"); return; } @@ -161,7 +161,7 @@ void acpi_ut_get_expected_return_types(char *buffer, u32 expected_btypes) /* If one of the expected types, concatenate the name of this type */ if (expected_btypes & this_rtype) { - ACPI_STRCAT(buffer, &ut_rtype_names[i][j]); + strcat(buffer, &ut_rtype_names[i][j]); j = 0; /* Use name separator from now on */ } diff --git a/drivers/acpi/acpica/utprint.c b/drivers/acpi/acpica/utprint.c index 2be6bd4bdc09..b26297c5de49 100644 --- a/drivers/acpi/acpica/utprint.c +++ b/drivers/acpi/acpica/utprint.c @@ -180,7 +180,7 @@ const char *acpi_ut_scan_number(const char *string, u64 *number_ptr) { u64 number = 0; - while (ACPI_IS_DIGIT(*string)) { + while (isdigit((int)*string)) { number *= 10; number += *(string++) - '0'; } @@ -405,7 +405,7 @@ acpi_ut_vsnprintf(char *string, /* Process width */ width = -1; - if (ACPI_IS_DIGIT(*format)) { + if (isdigit((int)*format)) { format = acpi_ut_scan_number(format, &number); width = (s32) number; } else if (*format == '*') { @@ -422,7 +422,7 @@ acpi_ut_vsnprintf(char *string, precision = -1; if (*format == '.') { ++format; - if (ACPI_IS_DIGIT(*format)) { + if (isdigit((int)*format)) { format = acpi_ut_scan_number(format, &number); precision = (s32) number; } else if (*format == '*') { diff --git a/drivers/acpi/acpica/utstring.c b/drivers/acpi/acpica/utstring.c index 83b6c52490dc..8f3c883dfe0e 100644 --- a/drivers/acpi/acpica/utstring.c +++ b/drivers/acpi/acpica/utstring.c @@ -79,7 +79,7 @@ void acpi_ut_strlwr(char *src_string) /* Walk entire string, lowercasing the letters */ for (string = src_string; *string; string++) { - *string = (char)ACPI_TOLOWER(*string); + *string = (char)tolower((int)*string); } return; @@ -145,7 +145,7 @@ void acpi_ut_strupr(char *src_string) /* Walk entire string, uppercasing the letters */ for (string = src_string; *string; string++) { - *string = (char)ACPI_TOUPPER(*string); + *string = (char)toupper((int)*string); } return; @@ -202,7 +202,7 @@ acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer) /* Skip over any white space in the buffer */ - while ((*string) && (ACPI_IS_SPACE(*string) || *string == '\t')) { + while ((*string) && (isspace((int)*string) || *string == '\t')) { string++; } @@ -211,7 +211,7 @@ acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer) * Base equal to ACPI_ANY_BASE means 'ToInteger operation case'. * We need to determine if it is decimal or hexadecimal. */ - if ((*string == '0') && (ACPI_TOLOWER(*(string + 1)) == 'x')) { + if ((*string == '0') && (tolower((int)*(string + 1)) == 'x')) { sign_of0x = 1; base = 16; @@ -224,7 +224,7 @@ acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer) /* Any string left? Check that '0x' is not followed by white space. */ - if (!(*string) || ACPI_IS_SPACE(*string) || *string == '\t') { + if (!(*string) || isspace((int)*string) || *string == '\t') { if (to_integer_op) { goto error_exit; } else { @@ -241,7 +241,7 @@ acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer) /* Main loop: convert the string to a 32- or 64-bit integer */ while (*string) { - if (ACPI_IS_DIGIT(*string)) { + if (isdigit((int)*string)) { /* Convert ASCII 0-9 to Decimal value */ @@ -252,8 +252,8 @@ acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer) term = 1; } else { - this_digit = (u8)ACPI_TOUPPER(*string); - if (ACPI_IS_XDIGIT((char)this_digit)) { + this_digit = (u8)toupper((int)*string); + if (isxdigit((int)this_digit)) { /* Convert ASCII Hex char to value */ @@ -404,7 +404,7 @@ void acpi_ut_print_string(char *string, u16 max_length) /* Check for printable character or hex escape */ - if (ACPI_IS_PRINT(string[i])) { + if (isprint((int)string[i])) { /* This is a normal character */ acpi_os_printf("%c", (int)string[i]); @@ -609,22 +609,22 @@ void ut_convert_backslashes(char *pathname) u8 acpi_ut_safe_strcpy(char *dest, acpi_size dest_size, char *source) { - if (ACPI_STRLEN(source) >= dest_size) { + if (strlen(source) >= dest_size) { return (TRUE); } - ACPI_STRCPY(dest, source); + strcpy(dest, source); return (FALSE); } u8 acpi_ut_safe_strcat(char *dest, acpi_size dest_size, char *source) { - if ((ACPI_STRLEN(dest) + ACPI_STRLEN(source)) >= dest_size) { + if ((strlen(dest) + strlen(source)) >= dest_size) { return (TRUE); } - ACPI_STRCAT(dest, source); + strcat(dest, source); return (FALSE); } @@ -635,14 +635,13 @@ acpi_ut_safe_strncat(char *dest, { acpi_size actual_transfer_length; - actual_transfer_length = - ACPI_MIN(max_transfer_length, ACPI_STRLEN(source)); + actual_transfer_length = ACPI_MIN(max_transfer_length, strlen(source)); - if ((ACPI_STRLEN(dest) + actual_transfer_length) >= dest_size) { + if ((strlen(dest) + actual_transfer_length) >= dest_size) { return (TRUE); } - ACPI_STRNCAT(dest, source, max_transfer_length); + strncat(dest, source, max_transfer_length); return (FALSE); } #endif diff --git a/drivers/acpi/acpica/uttrack.c b/drivers/acpi/acpica/uttrack.c index 130dd9f96f0f..9a7dc8196a5d 100644 --- a/drivers/acpi/acpica/uttrack.c +++ b/drivers/acpi/acpica/uttrack.c @@ -100,7 +100,7 @@ acpi_ut_create_list(char *list_name, return (AE_NO_MEMORY); } - ACPI_MEMSET(cache, 0, sizeof(struct acpi_memory_list)); + memset(cache, 0, sizeof(struct acpi_memory_list)); cache->list_name = list_name; cache->object_size = object_size; @@ -402,7 +402,7 @@ acpi_ut_track_allocation(struct acpi_debug_mem_block *allocation, allocation->component = component; allocation->line = line; - ACPI_STRNCPY(allocation->module, module, ACPI_MAX_MODULE_NAME); + strncpy(allocation->module, module, ACPI_MAX_MODULE_NAME); allocation->module[ACPI_MAX_MODULE_NAME - 1] = 0; if (!element) { @@ -497,7 +497,7 @@ acpi_ut_remove_allocation(struct acpi_debug_mem_block *allocation, /* Mark the segment as deleted */ - ACPI_MEMSET(&allocation->user_space, 0xEA, allocation->size); + memset(&allocation->user_space, 0xEA, allocation->size); status = acpi_ut_release_mutex(ACPI_MTX_MEMORY); return (status); @@ -595,7 +595,7 @@ void acpi_ut_dump_allocations(u32 component, const char *module) while (element) { if ((element->component & component) && ((module == NULL) - || (0 == ACPI_STRCMP(module, element->module)))) { + || (0 == strcmp(module, element->module)))) { descriptor = ACPI_CAST_PTR(union acpi_descriptor, &element->user_space); diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c index 0929187bdce0..51cf52d52243 100644 --- a/drivers/acpi/acpica/utxface.c +++ b/drivers/acpi/acpica/utxface.c @@ -234,8 +234,8 @@ acpi_status acpi_get_statistics(struct acpi_statistics *stats) stats->sci_count = acpi_sci_count; stats->gpe_count = acpi_gpe_count; - ACPI_MEMCPY(stats->fixed_event_count, acpi_fixed_event_count, - sizeof(acpi_fixed_event_count)); + memcpy(stats->fixed_event_count, acpi_fixed_event_count, + sizeof(acpi_fixed_event_count)); /* Other counters */ @@ -322,7 +322,7 @@ acpi_status acpi_install_interface(acpi_string interface_name) /* Parameter validation */ - if (!interface_name || (ACPI_STRLEN(interface_name) == 0)) { + if (!interface_name || (strlen(interface_name) == 0)) { return (AE_BAD_PARAMETER); } @@ -374,7 +374,7 @@ acpi_status acpi_remove_interface(acpi_string interface_name) /* Parameter validation */ - if (!interface_name || (ACPI_STRLEN(interface_name) == 0)) { + if (!interface_name || (strlen(interface_name) == 0)) { return (AE_BAD_PARAMETER); } diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index d791b986002a..c2a41d223162 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -542,14 +542,14 @@ typedef u64 acpi_integer; #define ACPI_COMPARE_NAME(a,b) (*ACPI_CAST_PTR (u32, (a)) == *ACPI_CAST_PTR (u32, (b))) #define ACPI_MOVE_NAME(dest,src) (*ACPI_CAST_PTR (u32, (dest)) = *ACPI_CAST_PTR (u32, (src))) #else -#define ACPI_COMPARE_NAME(a,b) (!ACPI_STRNCMP (ACPI_CAST_PTR (char, (a)), ACPI_CAST_PTR (char, (b)), ACPI_NAME_SIZE)) -#define ACPI_MOVE_NAME(dest,src) (ACPI_STRNCPY (ACPI_CAST_PTR (char, (dest)), ACPI_CAST_PTR (char, (src)), ACPI_NAME_SIZE)) +#define ACPI_COMPARE_NAME(a,b) (!strncmp (ACPI_CAST_PTR (char, (a)), ACPI_CAST_PTR (char, (b)), ACPI_NAME_SIZE)) +#define ACPI_MOVE_NAME(dest,src) (strncpy (ACPI_CAST_PTR (char, (dest)), ACPI_CAST_PTR (char, (src)), ACPI_NAME_SIZE)) #endif /* Support for the special RSDP signature (8 characters) */ -#define ACPI_VALIDATE_RSDP_SIG(a) (!ACPI_STRNCMP (ACPI_CAST_PTR (char, (a)), ACPI_SIG_RSDP, 8)) -#define ACPI_MAKE_RSDP_SIG(dest) (ACPI_MEMCPY (ACPI_CAST_PTR (char, (dest)), ACPI_SIG_RSDP, 8)) +#define ACPI_VALIDATE_RSDP_SIG(a) (!strncmp (ACPI_CAST_PTR (char, (a)), ACPI_SIG_RSDP, 8)) +#define ACPI_MAKE_RSDP_SIG(dest) (memcpy (ACPI_CAST_PTR (char, (dest)), ACPI_SIG_RSDP, 8)) /******************************************************************************* * diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h index 1e84e62b448d..3cedd43943f4 100644 --- a/include/acpi/platform/acenv.h +++ b/include/acpi/platform/acenv.h @@ -346,28 +346,6 @@ /* We will be linking to the standard Clib functions */ -#define ACPI_STRSTR(s1,s2) strstr((s1), (s2)) -#define ACPI_STRCHR(s1,c) strchr((s1), (c)) -#define ACPI_STRLEN(s) (acpi_size) strlen((s)) -#define ACPI_STRCPY(d,s) (void) strcpy((d), (s)) -#define ACPI_STRNCPY(d,s,n) (void) strncpy((d), (s), (acpi_size)(n)) -#define ACPI_STRNCMP(d,s,n) strncmp((d), (s), (acpi_size)(n)) -#define ACPI_STRCMP(d,s) strcmp((d), (s)) -#define ACPI_STRCAT(d,s) (void) strcat((d), (s)) -#define ACPI_STRNCAT(d,s,n) strncat((d), (s), (acpi_size)(n)) -#define ACPI_STRTOUL(d,s,n) strtoul((d), (s), (acpi_size)(n)) -#define ACPI_MEMCMP(s1,s2,n) memcmp((const char *)(s1), (const char *)(s2), (acpi_size)(n)) -#define ACPI_MEMCPY(d,s,n) (void) memcpy((d), (s), (acpi_size)(n)) -#define ACPI_MEMSET(d,s,n) (void) memset((d), (s), (acpi_size)(n)) -#define ACPI_TOUPPER(i) toupper((int) (i)) -#define ACPI_TOLOWER(i) tolower((int) (i)) -#define ACPI_IS_XDIGIT(i) isxdigit((int) (i)) -#define ACPI_IS_DIGIT(i) isdigit((int) (i)) -#define ACPI_IS_SPACE(i) isspace((int) (i)) -#define ACPI_IS_UPPER(i) isupper((int) (i)) -#define ACPI_IS_PRINT(i) isprint((int) (i)) -#define ACPI_IS_ALPHA(i) isalpha((int) (i)) - #else /****************************************************************************** @@ -405,22 +383,6 @@ typedef char *va_list; /* Use the local (ACPICA) definitions of the clib functions */ -#define ACPI_STRSTR(s1,s2) acpi_ut_strstr ((s1), (s2)) -#define ACPI_STRCHR(s1,c) acpi_ut_strchr ((s1), (c)) -#define ACPI_STRLEN(s) (acpi_size) acpi_ut_strlen ((s)) -#define ACPI_STRCPY(d,s) (void) acpi_ut_strcpy ((d), (s)) -#define ACPI_STRNCPY(d,s,n) (void) acpi_ut_strncpy ((d), (s), (acpi_size)(n)) -#define ACPI_STRNCMP(d,s,n) acpi_ut_strncmp ((d), (s), (acpi_size)(n)) -#define ACPI_STRCMP(d,s) acpi_ut_strcmp ((d), (s)) -#define ACPI_STRCAT(d,s) (void) acpi_ut_strcat ((d), (s)) -#define ACPI_STRNCAT(d,s,n) acpi_ut_strncat ((d), (s), (acpi_size)(n)) -#define ACPI_STRTOUL(d,s,n) acpi_ut_strtoul ((d), (s), (acpi_size)(n)) -#define ACPI_MEMCMP(s1,s2,n) acpi_ut_memcmp((const char *)(s1), (const char *)(s2), (acpi_size)(n)) -#define ACPI_MEMCPY(d,s,n) (void) acpi_ut_memcpy ((d), (s), (acpi_size)(n)) -#define ACPI_MEMSET(d,v,n) (void) acpi_ut_memset ((d), (v), (acpi_size)(n)) -#define ACPI_TOUPPER(c) acpi_ut_to_upper ((int) (c)) -#define ACPI_TOLOWER(c) acpi_ut_to_lower ((int) (c)) - #endif /* ACPI_USE_SYSTEM_CLIBRARY */ #ifndef ACPI_FILE diff --git a/tools/power/acpi/common/getopt.c b/tools/power/acpi/common/getopt.c index 5da129e10aa2..326e826a5d20 100644 --- a/tools/power/acpi/common/getopt.c +++ b/tools/power/acpi/common/getopt.c @@ -127,7 +127,7 @@ int acpi_getopt(int argc, char **argv, char *opts) argv[acpi_gbl_optind][0] != '-' || argv[acpi_gbl_optind][1] == '\0') { return (ACPI_OPT_END); - } else if (ACPI_STRCMP(argv[acpi_gbl_optind], "--") == 0) { + } else if (strcmp(argv[acpi_gbl_optind], "--") == 0) { acpi_gbl_optind++; return (ACPI_OPT_END); } @@ -140,7 +140,7 @@ int acpi_getopt(int argc, char **argv, char *opts) /* Make sure that the option is legal */ if (current_char == ':' || - (opts_ptr = ACPI_STRCHR(opts, current_char)) == NULL) { + (opts_ptr = strchr(opts, current_char)) == NULL) { ACPI_OPTION_ERROR("Illegal option: -", current_char); if (argv[acpi_gbl_optind][++current_char_ptr] == '\0') { diff --git a/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c index 3aff9a2c7088..dd5008b0617a 100644 --- a/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c +++ b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c @@ -222,7 +222,7 @@ acpi_os_get_table_by_address(acpi_physical_address address, goto exit; } - ACPI_MEMCPY(local_table, mapped_table, table_length); + memcpy(local_table, mapped_table, table_length); exit: osl_unmap_table(mapped_table); @@ -531,7 +531,7 @@ static acpi_status osl_load_rsdp(void) gbl_rsdp_address = rsdp_base + (ACPI_CAST8(mapped_table) - rsdp_address); - ACPI_MEMCPY(&gbl_rsdp, mapped_table, sizeof(struct acpi_table_rsdp)); + memcpy(&gbl_rsdp, mapped_table, sizeof(struct acpi_table_rsdp)); acpi_os_unmap_memory(rsdp_address, rsdp_size); return (AE_OK); @@ -964,7 +964,7 @@ osl_get_bios_table(char *signature, goto exit; } - ACPI_MEMCPY(local_table, mapped_table, table_length); + memcpy(local_table, mapped_table, table_length); *address = table_address; *table = local_table; diff --git a/tools/power/acpi/tools/acpidump/apdump.c b/tools/power/acpi/tools/acpidump/apdump.c index c736adf5fb55..61d0de804b70 100644 --- a/tools/power/acpi/tools/acpidump/apdump.c +++ b/tools/power/acpi/tools/acpidump/apdump.c @@ -329,7 +329,7 @@ int ap_dump_table_by_name(char *signature) acpi_status status; int table_status; - if (ACPI_STRLEN(signature) != ACPI_NAME_SIZE) { + if (strlen(signature) != ACPI_NAME_SIZE) { acpi_log_error ("Invalid table signature [%s]: must be exactly 4 characters\n", signature); @@ -338,15 +338,15 @@ int ap_dump_table_by_name(char *signature) /* Table signatures are expected to be uppercase */ - ACPI_STRCPY(local_signature, signature); + strcpy(local_signature, signature); acpi_ut_strupr(local_signature); /* To be friendly, handle tables whose signatures do not match the name */ if (ACPI_COMPARE_NAME(local_signature, "FADT")) { - ACPI_STRCPY(local_signature, ACPI_SIG_FADT); + strcpy(local_signature, ACPI_SIG_FADT); } else if (ACPI_COMPARE_NAME(local_signature, "MADT")) { - ACPI_STRCPY(local_signature, ACPI_SIG_MADT); + strcpy(local_signature, ACPI_SIG_MADT); } /* Dump all instances of this signature (to handle multiple SSDTs) */ diff --git a/tools/power/acpi/tools/acpidump/apfiles.c b/tools/power/acpi/tools/acpidump/apfiles.c index 8f2fe168228e..a37f9702b2a9 100644 --- a/tools/power/acpi/tools/acpidump/apfiles.c +++ b/tools/power/acpi/tools/acpidump/apfiles.c @@ -136,10 +136,10 @@ int ap_write_to_binary_file(struct acpi_table_header *table, u32 instance) } else { ACPI_MOVE_NAME(filename, table->signature); } - filename[0] = (char)ACPI_TOLOWER(filename[0]); - filename[1] = (char)ACPI_TOLOWER(filename[1]); - filename[2] = (char)ACPI_TOLOWER(filename[2]); - filename[3] = (char)ACPI_TOLOWER(filename[3]); + filename[0] = (char)tolower((int)filename[0]); + filename[1] = (char)tolower((int)filename[1]); + filename[2] = (char)tolower((int)filename[2]); + filename[3] = (char)tolower((int)filename[3]); filename[ACPI_NAME_SIZE] = 0; /* Handle multiple SSDts - create different filenames for each */ @@ -147,10 +147,10 @@ int ap_write_to_binary_file(struct acpi_table_header *table, u32 instance) if (instance > 0) { acpi_ut_snprintf(instance_str, sizeof(instance_str), "%u", instance); - ACPI_STRCAT(filename, instance_str); + strcat(filename, instance_str); } - ACPI_STRCAT(filename, ACPI_TABLE_FILE_SUFFIX); + strcat(filename, ACPI_TABLE_FILE_SUFFIX); if (gbl_verbose_mode) { acpi_log_error -- cgit v1.2.3-70-g09d2 From 747ef1b1ce32b824a25ce1e70934b58733dfa6f9 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 1 Jul 2015 14:45:18 +0800 Subject: ACPICA: Split C library prototypes to new header ACPICA commit f51bf8497889a94046820639537165bbd7ccdee6 Adds acclib.h This patch doesn't affect the Linux kernel. Link: https://github.com/acpica/acpica/commit/f51bf849 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/accommon.h | 3 +++ drivers/acpi/acpica/acutils.h | 58 ------------------------------------------ 2 files changed, 3 insertions(+), 58 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/accommon.h b/drivers/acpi/acpica/accommon.h index 853aa2dbdb61..a8d8092ee391 100644 --- a/drivers/acpi/acpica/accommon.h +++ b/drivers/acpi/acpica/accommon.h @@ -59,5 +59,8 @@ #include "acglobal.h" /* All global variables */ #include "achware.h" /* Hardware defines and interfaces */ #include "acutils.h" /* Utility interfaces */ +#ifndef ACPI_USE_SYSTEM_CLIBRARY +#include "acclib.h" /* C library interfaces */ +#endif /* !ACPI_USE_SYSTEM_CLIBRARY */ #endif /* __ACCOMMON_H__ */ diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index ef1e51d0f038..6de0d3573037 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -205,64 +205,6 @@ acpi_status acpi_ut_hardware_initialize(void); void acpi_ut_subsystem_shutdown(void); -/* - * utclib - Local implementations of C library functions - */ -#ifndef ACPI_USE_SYSTEM_CLIBRARY - -acpi_size strlen(const char *string); - -char *strchr(const char *string, int ch); - -char *strcpy(char *dst_string, const char *src_string); - -char *strncpy(char *dst_string, const char *src_string, acpi_size count); - -int strncmp(const char *string1, const char *string2, acpi_size count); - -int strcmp(const char *string1, const char *string2); - -char *strcat(char *dst_string, const char *src_string); - -char *strncat(char *dst_string, const char *src_string, acpi_size count); - -u32 strtoul(const char *string, char **terminator, u32 base); - -char *strstr(char *string1, char *string2); - -int memcmp(void *buffer1, void *buffer2, acpi_size count); - -void *memcpy(void *dest, const void *src, acpi_size count); - -void *memset(void *dest, int value, acpi_size count); - -int toupper(int c); - -int tolower(int c); - -extern const u8 _acpi_ctype[]; - -#define _ACPI_XA 0x00 /* extra alphabetic - not supported */ -#define _ACPI_XS 0x40 /* extra space */ -#define _ACPI_BB 0x00 /* BEL, BS, etc. - not supported */ -#define _ACPI_CN 0x20 /* CR, FF, HT, NL, VT */ -#define _ACPI_DI 0x04 /* '0'-'9' */ -#define _ACPI_LO 0x02 /* 'a'-'z' */ -#define _ACPI_PU 0x10 /* punctuation */ -#define _ACPI_SP 0x08 /* space, tab, CR, LF, VT, FF */ -#define _ACPI_UP 0x01 /* 'A'-'Z' */ -#define _ACPI_XD 0x80 /* '0'-'9', 'A'-'F', 'a'-'f' */ - -#define isdigit(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_DI)) -#define isspace(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_SP)) -#define isxdigit(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_XD)) -#define isupper(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_UP)) -#define islower(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_LO)) -#define isprint(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_LO | _ACPI_UP | _ACPI_DI | _ACPI_XS | _ACPI_PU)) -#define isalpha(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_LO | _ACPI_UP)) - -#endif /* !ACPI_USE_SYSTEM_CLIBRARY */ - #define ACPI_IS_ASCII(c) ((c) < 0x80) /* -- cgit v1.2.3-70-g09d2 From 3d2967b5b5b29a863227273639b84cfd39bba7f3 Mon Sep 17 00:00:00 2001 From: gongzg Date: Wed, 1 Jul 2015 14:45:38 +0800 Subject: ACPICA: Comment update, no functional change ACPICA commit 1a8ec7b83d55c7b957247d685bd1c73f6a012f1e Remove redundant comment in nseval.c Link: https://github.com/acpica/acpica/commit/1a8ec7b8 Signed-off-by: gongzg Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/nseval.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/nseval.c b/drivers/acpi/acpica/nseval.c index a725d88b036b..80670cb32b5a 100644 --- a/drivers/acpi/acpica/nseval.c +++ b/drivers/acpi/acpica/nseval.c @@ -59,15 +59,14 @@ acpi_ns_exec_module_code(union acpi_operand_object *method_obj, * * FUNCTION: acpi_ns_evaluate * - * PARAMETERS: info - Evaluation info block, contains: + * PARAMETERS: info - Evaluation info block, contains these fields + * and more: * prefix_node - Prefix or Method/Object Node to execute * relative_path - Name of method to execute, If NULL, the * Node is the object to execute * parameters - List of parameters to pass to the method, * terminated by NULL. Params itself may be * NULL if no parameters are being passed. - * return_object - Where to put method's return value (if - * any). If NULL, no value is returned. * parameter_type - Type of Parameter list * return_object - Where to put method's return value (if * any). If NULL, no value is returned. -- cgit v1.2.3-70-g09d2 From 75a15a7864c9e281c74a1670b10b69d1d7ff1c82 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Wed, 1 Jul 2015 13:38:52 +0300 Subject: EDAC, octeon: Fix broken build due to model helper renames Commit debe6a623d3c ("MIPS: OCTEON: Update octeon-model.h code for new SoCs.") renamed some SoC model helper functions, but forgot to update the EDAC drivers resulting in build failures. Fix that. Cc: stable@vger.kernel.org # v4.0+ Signed-off-by: Aaro Koskinen Acked-by: David Daney Cc: Mauro Carvalho Chehab Cc: Ralf Baechle Cc: linux-edac Cc: linux-mips@linux-mips.org Link: http://lkml.kernel.org/r/1435747132-10954-1-git-send-email-aaro.koskinen@nokia.com Signed-off-by: Borislav Petkov --- drivers/edac/octeon_edac-l2c.c | 2 +- drivers/edac/octeon_edac-lmc.c | 2 +- drivers/edac/octeon_edac-pc.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/octeon_edac-l2c.c b/drivers/edac/octeon_edac-l2c.c index 7e98084d3645..afea7fc625cc 100644 --- a/drivers/edac/octeon_edac-l2c.c +++ b/drivers/edac/octeon_edac-l2c.c @@ -151,7 +151,7 @@ static int octeon_l2c_probe(struct platform_device *pdev) l2c->ctl_name = "octeon_l2c_err"; - if (OCTEON_IS_MODEL(OCTEON_FAM_1_PLUS)) { + if (OCTEON_IS_OCTEON1PLUS()) { union cvmx_l2t_err l2t_err; union cvmx_l2d_err l2d_err; diff --git a/drivers/edac/octeon_edac-lmc.c b/drivers/edac/octeon_edac-lmc.c index bb19e0732681..cda6dab5067a 100644 --- a/drivers/edac/octeon_edac-lmc.c +++ b/drivers/edac/octeon_edac-lmc.c @@ -234,7 +234,7 @@ static int octeon_lmc_edac_probe(struct platform_device *pdev) layers[0].size = 1; layers[0].is_virt_csrow = false; - if (OCTEON_IS_MODEL(OCTEON_FAM_1_PLUS)) { + if (OCTEON_IS_OCTEON1PLUS()) { union cvmx_lmcx_mem_cfg0 cfg0; cfg0.u64 = cvmx_read_csr(CVMX_LMCX_MEM_CFG0(0)); diff --git a/drivers/edac/octeon_edac-pc.c b/drivers/edac/octeon_edac-pc.c index 0f83c33a7d1f..2ab6cf24c959 100644 --- a/drivers/edac/octeon_edac-pc.c +++ b/drivers/edac/octeon_edac-pc.c @@ -73,7 +73,7 @@ static int co_cache_error_event(struct notifier_block *this, edac_device_handle_ce(p->ed, cpu, 0, "dcache"); /* Clear the error indication */ - if (OCTEON_IS_MODEL(OCTEON_FAM_2)) + if (OCTEON_IS_OCTEON2()) write_octeon_c0_dcacheerr(1); else write_octeon_c0_dcacheerr(0); -- cgit v1.2.3-70-g09d2 From 0438ec90b17963662ef619b71c77c5c135b07014 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Tue, 30 Jun 2015 12:23:45 +0300 Subject: OMAPDSS: fix probing if rfbi device is enabled After the commit 736e60ddc215b85e73bbf7da26e1cde84cc9500f ("OMAPDSS: componentize omapdss") the dss core device will wait until all the subdevices have been successfully probed. However, we don't have a working driver for RFBI, so if RFBI device exists, omapdss will never get probed. All the .dtsi files set RFBI as disabled, except am4372.dtsi. This causes omapdss probe to not finish on AM4 devices. This patch makes omapdss driver skip adding rfbi device as a subcomponent, solving the issue. This should be reverted when we have a working RFBI driver. Signed-off-by: Tomi Valkeinen Reported-by: Felipe Balbi --- drivers/video/fbdev/omap2/dss/dss.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/video/fbdev/omap2/dss/dss.c b/drivers/video/fbdev/omap2/dss/dss.c index 612b093831d5..9200a8668b49 100644 --- a/drivers/video/fbdev/omap2/dss/dss.c +++ b/drivers/video/fbdev/omap2/dss/dss.c @@ -1225,6 +1225,15 @@ static int dss_add_child_component(struct device *dev, void *data) { struct component_match **match = data; + /* + * HACK + * We don't have a working driver for rfbi, so skip it here always. + * Otherwise dss will never get probed successfully, as it will wait + * for rfbi to get probed. + */ + if (strstr(dev_name(dev), "rfbi")) + return 0; + component_match_add(dev->parent, match, dss_component_compare, dev); return 0; -- cgit v1.2.3-70-g09d2 From c423bc85097327fba71f9a831280d09b64bb62b6 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Tue, 16 Jun 2015 14:54:51 +0300 Subject: drm/omap: check that plane is inside crtc DRM allows planes to be partially off-screen, but DSS hardware does not. This patch adds the necessary check to reject plane configs if the plane is not fully inside the crtc. Signed-off-by: Tomi Valkeinen Acked-by: Laurent Pinchart --- drivers/gpu/drm/omapdrm/omap_plane.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c index cfa8276c4deb..098904696a5c 100644 --- a/drivers/gpu/drm/omapdrm/omap_plane.c +++ b/drivers/gpu/drm/omapdrm/omap_plane.c @@ -17,6 +17,7 @@ * this program. If not, see . */ +#include #include #include @@ -153,9 +154,34 @@ static void omap_plane_atomic_disable(struct drm_plane *plane, dispc_ovl_enable(omap_plane->id, false); } +static int omap_plane_atomic_check(struct drm_plane *plane, + struct drm_plane_state *state) +{ + struct drm_crtc_state *crtc_state; + + if (!state->crtc) + return 0; + + crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + + if (state->crtc_x < 0 || state->crtc_y < 0) + return -EINVAL; + + if (state->crtc_x + state->crtc_w > crtc_state->adjusted_mode.hdisplay) + return -EINVAL; + + if (state->crtc_y + state->crtc_h > crtc_state->adjusted_mode.vdisplay) + return -EINVAL; + + return 0; +} + static const struct drm_plane_helper_funcs omap_plane_helper_funcs = { .prepare_fb = omap_plane_prepare_fb, .cleanup_fb = omap_plane_cleanup_fb, + .atomic_check = omap_plane_atomic_check, .atomic_update = omap_plane_atomic_update, .atomic_disable = omap_plane_atomic_disable, }; -- cgit v1.2.3-70-g09d2 From 96cbd142310cc7281f94739b27d8e4c308d588c5 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Tue, 28 Apr 2015 14:01:32 +0300 Subject: drm/omap: increase DMM transaction timeout The DMM driver uses a timeout of 1 ms to wait for DMM transaction to finish. While DMM should always finish the operation within that time, the timeout is rather strict. Small misbehavior of the system (e.g. an irq taking too long) could trigger the timeout. As the DMM is a critical piece of code for display memory management, let's increase the timeout to 100 ms so that we are less likely to fail a memory allocation in case of system misbehaviors. 100 ms is just a guess of a reasonably large timeout. The HW should accomplish the task in less than 1 ms. Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/omap_dmm_tiler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c index f2daad8c3d96..7841970de48d 100644 --- a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c +++ b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c @@ -285,7 +285,7 @@ static int dmm_txn_commit(struct dmm_txn *txn, bool wait) if (wait) { if (!wait_for_completion_timeout(&engine->compl, - msecs_to_jiffies(1))) { + msecs_to_jiffies(100))) { dev_err(dmm->dev, "timed out waiting for done\n"); ret = -ETIMEDOUT; } -- cgit v1.2.3-70-g09d2 From 9c368506c96793f17934a61a0f06412afb7d2f8d Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Tue, 28 Apr 2015 14:01:35 +0300 Subject: drm/omap: fix omap_framebuffer_unpin() error handling omap_framebuffer_unpin() check the return value of omap_gem_put_paddr() and return immediately if omap_gem_put_paddr() fails. This patch removes the check for the return value, and also removes the return value of omap_framebuffer_unpin(), because: * Nothing checks the return value of omap_framebuffer_unpin(), and even something did check it, there's nothing the caller can do to handle the error. * If a omap_gem_put_paddr() fails, the framebuffer's other planes will be left unreleased. So it's better to call omap_gem_put_paddr() for all the planes, even if one would fail. Signed-off-by: Tomi Valkeinen Acked-by: Laurent Pinchart --- drivers/gpu/drm/omapdrm/omap_drv.h | 2 +- drivers/gpu/drm/omapdrm/omap_fb.c | 16 ++++------------ 2 files changed, 5 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h index ae2df41f216f..2ef89c0c3006 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.h +++ b/drivers/gpu/drm/omapdrm/omap_drv.h @@ -177,7 +177,7 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev, struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos); struct drm_gem_object *omap_framebuffer_bo(struct drm_framebuffer *fb, int p); int omap_framebuffer_pin(struct drm_framebuffer *fb); -int omap_framebuffer_unpin(struct drm_framebuffer *fb); +void omap_framebuffer_unpin(struct drm_framebuffer *fb); void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, struct omap_drm_window *win, struct omap_overlay_info *info); struct drm_connector *omap_framebuffer_get_next_connector( diff --git a/drivers/gpu/drm/omapdrm/omap_fb.c b/drivers/gpu/drm/omapdrm/omap_fb.c index 0b967e76df1a..51b1219af87f 100644 --- a/drivers/gpu/drm/omapdrm/omap_fb.c +++ b/drivers/gpu/drm/omapdrm/omap_fb.c @@ -287,10 +287,10 @@ fail: } /* unpin, no longer being scanned out: */ -int omap_framebuffer_unpin(struct drm_framebuffer *fb) +void omap_framebuffer_unpin(struct drm_framebuffer *fb) { struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); - int ret, i, n = drm_format_num_planes(fb->pixel_format); + int i, n = drm_format_num_planes(fb->pixel_format); mutex_lock(&omap_fb->lock); @@ -298,24 +298,16 @@ int omap_framebuffer_unpin(struct drm_framebuffer *fb) if (omap_fb->pin_count > 0) { mutex_unlock(&omap_fb->lock); - return 0; + return; } for (i = 0; i < n; i++) { struct plane *plane = &omap_fb->planes[i]; - ret = omap_gem_put_paddr(plane->bo); - if (ret) - goto fail; + omap_gem_put_paddr(plane->bo); plane->paddr = 0; } mutex_unlock(&omap_fb->lock); - - return 0; - -fail: - mutex_unlock(&omap_fb->lock); - return ret; } struct drm_gem_object *omap_framebuffer_bo(struct drm_framebuffer *fb, int p) -- cgit v1.2.3-70-g09d2 From 393a949f51994a67e8e33b2f79c6f2020959a7e2 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Tue, 28 Apr 2015 14:01:36 +0300 Subject: drm/omap: fix omap_gem_put_paddr() error handling If tiler_unpin() call in omap_gem_put_paddr() fails, omap_gem_put_paddr() will immediately stop processing and return an error. This patch remoes that error checking, and also removes omap_gem_put_paddr()'s return value, because: * The caller of omap_gem_put_paddr() can do nothing if an error happens, so it's pointless to return an error value * If tiler_unpin() fails, the GEM object will possibly be left in an undefined state, where the DMM mapping may have been removed, but the GEM object still thinks everything is as it should be, leading to crashes later. * There's no point in returning an error from a "free" call, as the caller can do nothing about it. So it's better to clean up as much as possible. Signed-off-by: Tomi Valkeinen Acked-by: Laurent Pinchart --- drivers/gpu/drm/omapdrm/omap_drv.h | 2 +- drivers/gpu/drm/omapdrm/omap_gem.c | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h index 2ef89c0c3006..1ae8477e4289 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.h +++ b/drivers/gpu/drm/omapdrm/omap_drv.h @@ -211,7 +211,7 @@ void omap_gem_dma_sync(struct drm_gem_object *obj, enum dma_data_direction dir); int omap_gem_get_paddr(struct drm_gem_object *obj, dma_addr_t *paddr, bool remap); -int omap_gem_put_paddr(struct drm_gem_object *obj); +void omap_gem_put_paddr(struct drm_gem_object *obj); int omap_gem_get_pages(struct drm_gem_object *obj, struct page ***pages, bool remap); int omap_gem_put_pages(struct drm_gem_object *obj); diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c index 874eb6dcf94b..7ed08fdc4c42 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.c +++ b/drivers/gpu/drm/omapdrm/omap_gem.c @@ -808,10 +808,10 @@ fail: /* Release physical address, when DMA is no longer being performed.. this * could potentially unpin and unmap buffers from TILER */ -int omap_gem_put_paddr(struct drm_gem_object *obj) +void omap_gem_put_paddr(struct drm_gem_object *obj) { struct omap_gem_object *omap_obj = to_omap_bo(obj); - int ret = 0; + int ret; mutex_lock(&obj->dev->struct_mutex); if (omap_obj->paddr_cnt > 0) { @@ -821,7 +821,6 @@ int omap_gem_put_paddr(struct drm_gem_object *obj) if (ret) { dev_err(obj->dev->dev, "could not unpin pages: %d\n", ret); - goto fail; } ret = tiler_release(omap_obj->block); if (ret) { @@ -832,9 +831,8 @@ int omap_gem_put_paddr(struct drm_gem_object *obj) omap_obj->block = NULL; } } -fail: + mutex_unlock(&obj->dev->struct_mutex); - return ret; } /* Get rotated scanout address (only valid if already pinned), at the -- cgit v1.2.3-70-g09d2 From d642d3acd89454006fd6ca9cc4dd57f26959f9d1 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Fri, 8 May 2015 13:32:31 +0300 Subject: drm/omap: fix align_pitch() for 24 bits per pixel align_pitch() uses ALIGN() to ensure the pitch is aligned to SGX's requirement of 8 pixels. However, ALIGN() expects the alignment value to be a power of two, which is not the case for 24 bits per pixels. Use roundup() instead, which works for all alignments. This fixes the error seen with 24 bits per pixel modes: "buffer pitch (2176 bytes) is not a multiple of pixel size (3 bytes)" Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/omap_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h index 1ae8477e4289..12081e61d45a 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.h +++ b/drivers/gpu/drm/omapdrm/omap_drv.h @@ -236,7 +236,7 @@ static inline int align_pitch(int pitch, int width, int bpp) /* PVR needs alignment to 8 pixels.. right now that is the most * restrictive stride requirement.. */ - return ALIGN(pitch, 8 * bytespp); + return roundup(pitch, 8 * bytespp); } /* map crtc to vblank mask */ -- cgit v1.2.3-70-g09d2 From 743c16719f671c206923d23dae4ac57edfd9483c Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Tue, 1 Jul 2014 20:52:50 +0200 Subject: drm/omap: replace ALIGN(PAGE_SIZE) by PAGE_ALIGN use mm.h definition Cc: David Airlie Cc: Tomi Valkeinen Cc: dri-devel@lists.freedesktop.org Signed-off-by: Fabian Frederick Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/omap_fbdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c index 23b5a84389e3..720d16bce7e8 100644 --- a/drivers/gpu/drm/omapdrm/omap_fbdev.c +++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c @@ -135,7 +135,7 @@ static int omap_fbdev_create(struct drm_fb_helper *helper, fbdev->ywrap_enabled = priv->has_dmm && ywrap_enabled; if (fbdev->ywrap_enabled) { /* need to align pitch to page size if using DMM scrolling */ - mode_cmd.pitches[0] = ALIGN(mode_cmd.pitches[0], PAGE_SIZE); + mode_cmd.pitches[0] = PAGE_ALIGN(mode_cmd.pitches[0]); } /* allocate backing bo */ -- cgit v1.2.3-70-g09d2 From ec110bc7cc48d7806c9b65094e6afb19452d458f Mon Sep 17 00:00:00 2001 From: Allen Hubbe Date: Thu, 7 May 2015 06:45:21 -0400 Subject: NTB: Move files in preparation for NTB abstraction This patch only moves files to their new locations, before applying the next two patches adding the NTB Abstraction layer. Splitting this patch from the next is intended make distinct which code is changed only due to moving the files, versus which are substantial code changes in adding the NTB Abstraction layer. Signed-off-by: Allen Hubbe Signed-off-by: Jon Mason --- drivers/net/Kconfig | 4 +- drivers/net/ntb_netdev.c | 6 +- drivers/ntb/Makefile | 4 +- drivers/ntb/hw/intel/ntb_hw_intel.c | 1894 ++++++++++++++++++++++++++++++++++ drivers/ntb/hw/intel/ntb_hw_intel.h | 385 +++++++ drivers/ntb/ntb_hw.c | 1895 ----------------------------------- drivers/ntb/ntb_hw.h | 256 ----- drivers/ntb/ntb_regs.h | 177 ---- drivers/ntb/ntb_transport.c | 14 +- include/linux/ntb.h | 88 -- include/linux/ntb_transport.h | 88 ++ 11 files changed, 2381 insertions(+), 2430 deletions(-) create mode 100644 drivers/ntb/hw/intel/ntb_hw_intel.c create mode 100644 drivers/ntb/hw/intel/ntb_hw_intel.h delete mode 100644 drivers/ntb/ntb_hw.c delete mode 100644 drivers/ntb/ntb_hw.h delete mode 100644 drivers/ntb/ntb_regs.h delete mode 100644 include/linux/ntb.h create mode 100644 include/linux/ntb_transport.h (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index df51d6025a90..bda3cde62bb3 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -203,8 +203,8 @@ config NET_POLL_CONTROLLER def_bool NETPOLL config NTB_NETDEV - tristate "Virtual Ethernet over NTB" - depends on NTB + tristate "Virtual Ethernet over NTB Transport" + depends on NTB_TRANSPORT config RIONET tristate "RapidIO Ethernet over messaging driver support" diff --git a/drivers/net/ntb_netdev.c b/drivers/net/ntb_netdev.c index 5a7e6397440a..6d3bfa62f5ec 100644 --- a/drivers/net/ntb_netdev.c +++ b/drivers/net/ntb_netdev.c @@ -49,7 +49,7 @@ #include #include #include -#include +#include #define NTB_NETDEV_VER "0.7" @@ -410,13 +410,13 @@ static int __init ntb_netdev_init_module(void) rc = ntb_register_client_dev(KBUILD_MODNAME); if (rc) return rc; - return ntb_register_client(&ntb_netdev_client); + return ntb_transport_register_client(&ntb_netdev_client); } module_init(ntb_netdev_init_module); static void __exit ntb_netdev_exit_module(void) { - ntb_unregister_client(&ntb_netdev_client); + ntb_transport_unregister_client(&ntb_netdev_client); ntb_unregister_client_dev(KBUILD_MODNAME); } module_exit(ntb_netdev_exit_module); diff --git a/drivers/ntb/Makefile b/drivers/ntb/Makefile index 15cb59fd354e..545b10a131af 100644 --- a/drivers/ntb/Makefile +++ b/drivers/ntb/Makefile @@ -1,3 +1,3 @@ -obj-$(CONFIG_NTB) += ntb.o +obj-$(CONFIG_NTB) += ntb_hw_intel.o -ntb-objs := ntb_hw.o ntb_transport.o +ntb_hw_intel-objs := hw/intel/ntb_hw_intel.o ntb_transport.o diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c new file mode 100644 index 000000000000..044534a995f1 --- /dev/null +++ b/drivers/ntb/hw/intel/ntb_hw_intel.c @@ -0,0 +1,1894 @@ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2012 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * BSD LICENSE + * + * Copyright(c) 2012 Intel Corporation. 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 copy + * 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. + * + * Intel PCIe NTB Linux driver + * + * Contact Information: + * Jon Mason + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "ntb_hw_intel.h" + +#define NTB_NAME "Intel(R) PCI-E Non-Transparent Bridge Driver" +#define NTB_VER "1.0" + +MODULE_DESCRIPTION(NTB_NAME); +MODULE_VERSION(NTB_VER); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("Intel Corporation"); + +enum { + NTB_CONN_TRANSPARENT = 0, + NTB_CONN_B2B, + NTB_CONN_RP, +}; + +enum { + NTB_DEV_USD = 0, + NTB_DEV_DSD, +}; + +enum { + SNB_HW = 0, + BWD_HW, +}; + +static struct dentry *debugfs_dir; + +#define BWD_LINK_RECOVERY_TIME 500 + +/* Translate memory window 0,1,2 to BAR 2,4,5 */ +#define MW_TO_BAR(mw) (mw == 0 ? 2 : (mw == 1 ? 4 : 5)) + +static const struct pci_device_id ntb_pci_tbl[] = { + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_BWD)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_JSF)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_SNB)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_IVT)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_HSX)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_JSF)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_SNB)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_IVT)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_HSX)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_JSF)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_SNB)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_IVT)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_HSX)}, + {0} +}; +MODULE_DEVICE_TABLE(pci, ntb_pci_tbl); + +static int is_ntb_xeon(struct ntb_device *ndev) +{ + switch (ndev->pdev->device) { + case PCI_DEVICE_ID_INTEL_NTB_SS_JSF: + case PCI_DEVICE_ID_INTEL_NTB_SS_SNB: + case PCI_DEVICE_ID_INTEL_NTB_SS_IVT: + case PCI_DEVICE_ID_INTEL_NTB_SS_HSX: + case PCI_DEVICE_ID_INTEL_NTB_PS_JSF: + case PCI_DEVICE_ID_INTEL_NTB_PS_SNB: + case PCI_DEVICE_ID_INTEL_NTB_PS_IVT: + case PCI_DEVICE_ID_INTEL_NTB_PS_HSX: + case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF: + case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB: + case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT: + case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX: + return 1; + default: + return 0; + } + + return 0; +} + +static int is_ntb_atom(struct ntb_device *ndev) +{ + switch (ndev->pdev->device) { + case PCI_DEVICE_ID_INTEL_NTB_B2B_BWD: + return 1; + default: + return 0; + } + + return 0; +} + +static void ntb_set_errata_flags(struct ntb_device *ndev) +{ + switch (ndev->pdev->device) { + /* + * this workaround applies to all platform up to IvyBridge + * Haswell has splitbar support and use a different workaround + */ + case PCI_DEVICE_ID_INTEL_NTB_SS_JSF: + case PCI_DEVICE_ID_INTEL_NTB_SS_SNB: + case PCI_DEVICE_ID_INTEL_NTB_SS_IVT: + case PCI_DEVICE_ID_INTEL_NTB_SS_HSX: + case PCI_DEVICE_ID_INTEL_NTB_PS_JSF: + case PCI_DEVICE_ID_INTEL_NTB_PS_SNB: + case PCI_DEVICE_ID_INTEL_NTB_PS_IVT: + case PCI_DEVICE_ID_INTEL_NTB_PS_HSX: + case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF: + case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB: + case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT: + case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX: + ndev->wa_flags |= WA_SNB_ERR; + break; + } +} + +/** + * ntb_register_event_callback() - register event callback + * @ndev: pointer to ntb_device instance + * @func: callback function to register + * + * This function registers a callback for any HW driver events such as link + * up/down, power management notices and etc. + * + * RETURNS: An appropriate -ERRNO error value on error, or zero for success. + */ +int ntb_register_event_callback(struct ntb_device *ndev, + void (*func)(void *handle, + enum ntb_hw_event event)) +{ + if (ndev->event_cb) + return -EINVAL; + + ndev->event_cb = func; + + return 0; +} + +/** + * ntb_unregister_event_callback() - unregisters the event callback + * @ndev: pointer to ntb_device instance + * + * This function unregisters the existing callback from transport + */ +void ntb_unregister_event_callback(struct ntb_device *ndev) +{ + ndev->event_cb = NULL; +} + +static void ntb_irq_work(unsigned long data) +{ + struct ntb_db_cb *db_cb = (struct ntb_db_cb *)data; + int rc; + + rc = db_cb->callback(db_cb->data, db_cb->db_num); + if (rc) + tasklet_schedule(&db_cb->irq_work); + else { + struct ntb_device *ndev = db_cb->ndev; + unsigned long mask; + + mask = readw(ndev->reg_ofs.ldb_mask); + clear_bit(db_cb->db_num * ndev->bits_per_vector, &mask); + writew(mask, ndev->reg_ofs.ldb_mask); + } +} + +/** + * ntb_register_db_callback() - register a callback for doorbell interrupt + * @ndev: pointer to ntb_device instance + * @idx: doorbell index to register callback, zero based + * @data: pointer to be returned to caller with every callback + * @func: callback function to register + * + * This function registers a callback function for the doorbell interrupt + * on the primary side. The function will unmask the doorbell as well to + * allow interrupt. + * + * RETURNS: An appropriate -ERRNO error value on error, or zero for success. + */ +int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx, + void *data, int (*func)(void *data, int db_num)) +{ + unsigned long mask; + + if (idx >= ndev->max_cbs || ndev->db_cb[idx].callback) { + dev_warn(&ndev->pdev->dev, "Invalid Index.\n"); + return -EINVAL; + } + + ndev->db_cb[idx].callback = func; + ndev->db_cb[idx].data = data; + ndev->db_cb[idx].ndev = ndev; + + tasklet_init(&ndev->db_cb[idx].irq_work, ntb_irq_work, + (unsigned long) &ndev->db_cb[idx]); + + /* unmask interrupt */ + mask = readw(ndev->reg_ofs.ldb_mask); + clear_bit(idx * ndev->bits_per_vector, &mask); + writew(mask, ndev->reg_ofs.ldb_mask); + + return 0; +} + +/** + * ntb_unregister_db_callback() - unregister a callback for doorbell interrupt + * @ndev: pointer to ntb_device instance + * @idx: doorbell index to register callback, zero based + * + * This function unregisters a callback function for the doorbell interrupt + * on the primary side. The function will also mask the said doorbell. + */ +void ntb_unregister_db_callback(struct ntb_device *ndev, unsigned int idx) +{ + unsigned long mask; + + if (idx >= ndev->max_cbs || !ndev->db_cb[idx].callback) + return; + + mask = readw(ndev->reg_ofs.ldb_mask); + set_bit(idx * ndev->bits_per_vector, &mask); + writew(mask, ndev->reg_ofs.ldb_mask); + + tasklet_disable(&ndev->db_cb[idx].irq_work); + + ndev->db_cb[idx].callback = NULL; +} + +/** + * ntb_find_transport() - find the transport pointer + * @transport: pointer to pci device + * + * Given the pci device pointer, return the transport pointer passed in when + * the transport attached when it was inited. + * + * RETURNS: pointer to transport. + */ +void *ntb_find_transport(struct pci_dev *pdev) +{ + struct ntb_device *ndev = pci_get_drvdata(pdev); + return ndev->ntb_transport; +} + +/** + * ntb_register_transport() - Register NTB transport with NTB HW driver + * @transport: transport identifier + * + * This function allows a transport to reserve the hardware driver for + * NTB usage. + * + * RETURNS: pointer to ntb_device, NULL on error. + */ +struct ntb_device *ntb_register_transport(struct pci_dev *pdev, void *transport) +{ + struct ntb_device *ndev = pci_get_drvdata(pdev); + + if (ndev->ntb_transport) + return NULL; + + ndev->ntb_transport = transport; + return ndev; +} + +/** + * ntb_unregister_transport() - Unregister the transport with the NTB HW driver + * @ndev - ntb_device of the transport to be freed + * + * This function unregisters the transport from the HW driver and performs any + * necessary cleanups. + */ +void ntb_unregister_transport(struct ntb_device *ndev) +{ + int i; + + if (!ndev->ntb_transport) + return; + + for (i = 0; i < ndev->max_cbs; i++) + ntb_unregister_db_callback(ndev, i); + + ntb_unregister_event_callback(ndev); + ndev->ntb_transport = NULL; +} + +/** + * ntb_write_local_spad() - write to the secondary scratchpad register + * @ndev: pointer to ntb_device instance + * @idx: index to the scratchpad register, 0 based + * @val: the data value to put into the register + * + * This function allows writing of a 32bit value to the indexed scratchpad + * register. This writes over the data mirrored to the local scratchpad register + * by the remote system. + * + * RETURNS: An appropriate -ERRNO error value on error, or zero for success. + */ +int ntb_write_local_spad(struct ntb_device *ndev, unsigned int idx, u32 val) +{ + if (idx >= ndev->limits.max_spads) + return -EINVAL; + + dev_dbg(&ndev->pdev->dev, "Writing %x to local scratch pad index %d\n", + val, idx); + writel(val, ndev->reg_ofs.spad_read + idx * 4); + + return 0; +} + +/** + * ntb_read_local_spad() - read from the primary scratchpad register + * @ndev: pointer to ntb_device instance + * @idx: index to scratchpad register, 0 based + * @val: pointer to 32bit integer for storing the register value + * + * This function allows reading of the 32bit scratchpad register on + * the primary (internal) side. This allows the local system to read data + * written and mirrored to the scratchpad register by the remote system. + * + * RETURNS: An appropriate -ERRNO error value on error, or zero for success. + */ +int ntb_read_local_spad(struct ntb_device *ndev, unsigned int idx, u32 *val) +{ + if (idx >= ndev->limits.max_spads) + return -EINVAL; + + *val = readl(ndev->reg_ofs.spad_write + idx * 4); + dev_dbg(&ndev->pdev->dev, + "Reading %x from local scratch pad index %d\n", *val, idx); + + return 0; +} + +/** + * ntb_write_remote_spad() - write to the secondary scratchpad register + * @ndev: pointer to ntb_device instance + * @idx: index to the scratchpad register, 0 based + * @val: the data value to put into the register + * + * This function allows writing of a 32bit value to the indexed scratchpad + * register. The register resides on the secondary (external) side. This allows + * the local system to write data to be mirrored to the remote systems + * scratchpad register. + * + * RETURNS: An appropriate -ERRNO error value on error, or zero for success. + */ +int ntb_write_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 val) +{ + if (idx >= ndev->limits.max_spads) + return -EINVAL; + + dev_dbg(&ndev->pdev->dev, "Writing %x to remote scratch pad index %d\n", + val, idx); + writel(val, ndev->reg_ofs.spad_write + idx * 4); + + return 0; +} + +/** + * ntb_read_remote_spad() - read from the primary scratchpad register + * @ndev: pointer to ntb_device instance + * @idx: index to scratchpad register, 0 based + * @val: pointer to 32bit integer for storing the register value + * + * This function allows reading of the 32bit scratchpad register on + * the primary (internal) side. This alloows the local system to read the data + * it wrote to be mirrored on the remote system. + * + * RETURNS: An appropriate -ERRNO error value on error, or zero for success. + */ +int ntb_read_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 *val) +{ + if (idx >= ndev->limits.max_spads) + return -EINVAL; + + *val = readl(ndev->reg_ofs.spad_read + idx * 4); + dev_dbg(&ndev->pdev->dev, + "Reading %x from remote scratch pad index %d\n", *val, idx); + + return 0; +} + +/** + * ntb_get_mw_base() - get addr for the NTB memory window + * @ndev: pointer to ntb_device instance + * @mw: memory window number + * + * This function provides the base address of the memory window specified. + * + * RETURNS: address, or NULL on error. + */ +resource_size_t ntb_get_mw_base(struct ntb_device *ndev, unsigned int mw) +{ + if (mw >= ntb_max_mw(ndev)) + return 0; + + return pci_resource_start(ndev->pdev, MW_TO_BAR(mw)); +} + +/** + * ntb_get_mw_vbase() - get virtual addr for the NTB memory window + * @ndev: pointer to ntb_device instance + * @mw: memory window number + * + * This function provides the base virtual address of the memory window + * specified. + * + * RETURNS: pointer to virtual address, or NULL on error. + */ +void __iomem *ntb_get_mw_vbase(struct ntb_device *ndev, unsigned int mw) +{ + if (mw >= ntb_max_mw(ndev)) + return NULL; + + return ndev->mw[mw].vbase; +} + +/** + * ntb_get_mw_size() - return size of NTB memory window + * @ndev: pointer to ntb_device instance + * @mw: memory window number + * + * This function provides the physical size of the memory window specified + * + * RETURNS: the size of the memory window or zero on error + */ +u64 ntb_get_mw_size(struct ntb_device *ndev, unsigned int mw) +{ + if (mw >= ntb_max_mw(ndev)) + return 0; + + return ndev->mw[mw].bar_sz; +} + +/** + * ntb_set_mw_addr - set the memory window address + * @ndev: pointer to ntb_device instance + * @mw: memory window number + * @addr: base address for data + * + * This function sets the base physical address of the memory window. This + * memory address is where data from the remote system will be transfered into + * or out of depending on how the transport is configured. + */ +void ntb_set_mw_addr(struct ntb_device *ndev, unsigned int mw, u64 addr) +{ + if (mw >= ntb_max_mw(ndev)) + return; + + dev_dbg(&ndev->pdev->dev, "Writing addr %Lx to BAR %d\n", addr, + MW_TO_BAR(mw)); + + ndev->mw[mw].phys_addr = addr; + + switch (MW_TO_BAR(mw)) { + case NTB_BAR_23: + writeq(addr, ndev->reg_ofs.bar2_xlat); + break; + case NTB_BAR_4: + if (ndev->split_bar) + writel(addr, ndev->reg_ofs.bar4_xlat); + else + writeq(addr, ndev->reg_ofs.bar4_xlat); + break; + case NTB_BAR_5: + writel(addr, ndev->reg_ofs.bar5_xlat); + break; + } +} + +/** + * ntb_ring_doorbell() - Set the doorbell on the secondary/external side + * @ndev: pointer to ntb_device instance + * @db: doorbell to ring + * + * This function allows triggering of a doorbell on the secondary/external + * side that will initiate an interrupt on the remote host + * + * RETURNS: An appropriate -ERRNO error value on error, or zero for success. + */ +void ntb_ring_doorbell(struct ntb_device *ndev, unsigned int db) +{ + dev_dbg(&ndev->pdev->dev, "%s: ringing doorbell %d\n", __func__, db); + + if (ndev->hw_type == BWD_HW) + writeq((u64) 1 << db, ndev->reg_ofs.rdb); + else + writew(((1 << ndev->bits_per_vector) - 1) << + (db * ndev->bits_per_vector), ndev->reg_ofs.rdb); +} + +static void bwd_recover_link(struct ntb_device *ndev) +{ + u32 status; + + /* Driver resets the NTB ModPhy lanes - magic! */ + writeb(0xe0, ndev->reg_base + BWD_MODPHY_PCSREG6); + writeb(0x40, ndev->reg_base + BWD_MODPHY_PCSREG4); + writeb(0x60, ndev->reg_base + BWD_MODPHY_PCSREG4); + writeb(0x60, ndev->reg_base + BWD_MODPHY_PCSREG6); + + /* Driver waits 100ms to allow the NTB ModPhy to settle */ + msleep(100); + + /* Clear AER Errors, write to clear */ + status = readl(ndev->reg_base + BWD_ERRCORSTS_OFFSET); + dev_dbg(&ndev->pdev->dev, "ERRCORSTS = %x\n", status); + status &= PCI_ERR_COR_REP_ROLL; + writel(status, ndev->reg_base + BWD_ERRCORSTS_OFFSET); + + /* Clear unexpected electrical idle event in LTSSM, write to clear */ + status = readl(ndev->reg_base + BWD_LTSSMERRSTS0_OFFSET); + dev_dbg(&ndev->pdev->dev, "LTSSMERRSTS0 = %x\n", status); + status |= BWD_LTSSMERRSTS0_UNEXPECTEDEI; + writel(status, ndev->reg_base + BWD_LTSSMERRSTS0_OFFSET); + + /* Clear DeSkew Buffer error, write to clear */ + status = readl(ndev->reg_base + BWD_DESKEWSTS_OFFSET); + dev_dbg(&ndev->pdev->dev, "DESKEWSTS = %x\n", status); + status |= BWD_DESKEWSTS_DBERR; + writel(status, ndev->reg_base + BWD_DESKEWSTS_OFFSET); + + status = readl(ndev->reg_base + BWD_IBSTERRRCRVSTS0_OFFSET); + dev_dbg(&ndev->pdev->dev, "IBSTERRRCRVSTS0 = %x\n", status); + status &= BWD_IBIST_ERR_OFLOW; + writel(status, ndev->reg_base + BWD_IBSTERRRCRVSTS0_OFFSET); + + /* Releases the NTB state machine to allow the link to retrain */ + status = readl(ndev->reg_base + BWD_LTSSMSTATEJMP_OFFSET); + dev_dbg(&ndev->pdev->dev, "LTSSMSTATEJMP = %x\n", status); + status &= ~BWD_LTSSMSTATEJMP_FORCEDETECT; + writel(status, ndev->reg_base + BWD_LTSSMSTATEJMP_OFFSET); +} + +static void ntb_link_event(struct ntb_device *ndev, int link_state) +{ + unsigned int event; + + if (ndev->link_status == link_state) + return; + + if (link_state == NTB_LINK_UP) { + u16 status; + + dev_info(&ndev->pdev->dev, "Link Up\n"); + ndev->link_status = NTB_LINK_UP; + event = NTB_EVENT_HW_LINK_UP; + + if (is_ntb_atom(ndev) || + ndev->conn_type == NTB_CONN_TRANSPARENT) + status = readw(ndev->reg_ofs.lnk_stat); + else { + int rc = pci_read_config_word(ndev->pdev, + SNB_LINK_STATUS_OFFSET, + &status); + if (rc) + return; + } + + ndev->link_width = (status & NTB_LINK_WIDTH_MASK) >> 4; + ndev->link_speed = (status & NTB_LINK_SPEED_MASK); + dev_info(&ndev->pdev->dev, "Link Width %d, Link Speed %d\n", + ndev->link_width, ndev->link_speed); + } else { + dev_info(&ndev->pdev->dev, "Link Down\n"); + ndev->link_status = NTB_LINK_DOWN; + event = NTB_EVENT_HW_LINK_DOWN; + /* Don't modify link width/speed, we need it in link recovery */ + } + + /* notify the upper layer if we have an event change */ + if (ndev->event_cb) + ndev->event_cb(ndev->ntb_transport, event); +} + +static int ntb_link_status(struct ntb_device *ndev) +{ + int link_state; + + if (is_ntb_atom(ndev)) { + u32 ntb_cntl; + + ntb_cntl = readl(ndev->reg_ofs.lnk_cntl); + if (ntb_cntl & BWD_CNTL_LINK_DOWN) + link_state = NTB_LINK_DOWN; + else + link_state = NTB_LINK_UP; + } else { + u16 status; + int rc; + + rc = pci_read_config_word(ndev->pdev, SNB_LINK_STATUS_OFFSET, + &status); + if (rc) + return rc; + + if (status & NTB_LINK_STATUS_ACTIVE) + link_state = NTB_LINK_UP; + else + link_state = NTB_LINK_DOWN; + } + + ntb_link_event(ndev, link_state); + + return 0; +} + +static void bwd_link_recovery(struct work_struct *work) +{ + struct ntb_device *ndev = container_of(work, struct ntb_device, + lr_timer.work); + u32 status32; + + bwd_recover_link(ndev); + /* There is a potential race between the 2 NTB devices recovering at the + * same time. If the times are the same, the link will not recover and + * the driver will be stuck in this loop forever. Add a random interval + * to the recovery time to prevent this race. + */ + msleep(BWD_LINK_RECOVERY_TIME + prandom_u32() % BWD_LINK_RECOVERY_TIME); + + status32 = readl(ndev->reg_base + BWD_LTSSMSTATEJMP_OFFSET); + if (status32 & BWD_LTSSMSTATEJMP_FORCEDETECT) + goto retry; + + status32 = readl(ndev->reg_base + BWD_IBSTERRRCRVSTS0_OFFSET); + if (status32 & BWD_IBIST_ERR_OFLOW) + goto retry; + + status32 = readl(ndev->reg_ofs.lnk_cntl); + if (!(status32 & BWD_CNTL_LINK_DOWN)) { + unsigned char speed, width; + u16 status16; + + status16 = readw(ndev->reg_ofs.lnk_stat); + width = (status16 & NTB_LINK_WIDTH_MASK) >> 4; + speed = (status16 & NTB_LINK_SPEED_MASK); + if (ndev->link_width != width || ndev->link_speed != speed) + goto retry; + } + + schedule_delayed_work(&ndev->hb_timer, NTB_HB_TIMEOUT); + return; + +retry: + schedule_delayed_work(&ndev->lr_timer, NTB_HB_TIMEOUT); +} + +/* BWD doesn't have link status interrupt, poll on that platform */ +static void bwd_link_poll(struct work_struct *work) +{ + struct ntb_device *ndev = container_of(work, struct ntb_device, + hb_timer.work); + unsigned long ts = jiffies; + + /* If we haven't gotten an interrupt in a while, check the BWD link + * status bit + */ + if (ts > ndev->last_ts + NTB_HB_TIMEOUT) { + int rc = ntb_link_status(ndev); + if (rc) + dev_err(&ndev->pdev->dev, + "Error determining link status\n"); + + /* Check to see if a link error is the cause of the link down */ + if (ndev->link_status == NTB_LINK_DOWN) { + u32 status32 = readl(ndev->reg_base + + BWD_LTSSMSTATEJMP_OFFSET); + if (status32 & BWD_LTSSMSTATEJMP_FORCEDETECT) { + schedule_delayed_work(&ndev->lr_timer, 0); + return; + } + } + } + + schedule_delayed_work(&ndev->hb_timer, NTB_HB_TIMEOUT); +} + +static int ntb_xeon_setup(struct ntb_device *ndev) +{ + switch (ndev->conn_type) { + case NTB_CONN_B2B: + ndev->reg_ofs.ldb = ndev->reg_base + SNB_PDOORBELL_OFFSET; + ndev->reg_ofs.ldb_mask = ndev->reg_base + SNB_PDBMSK_OFFSET; + ndev->reg_ofs.spad_read = ndev->reg_base + SNB_SPAD_OFFSET; + ndev->reg_ofs.bar2_xlat = ndev->reg_base + SNB_SBAR2XLAT_OFFSET; + ndev->reg_ofs.bar4_xlat = ndev->reg_base + SNB_SBAR4XLAT_OFFSET; + if (ndev->split_bar) + ndev->reg_ofs.bar5_xlat = + ndev->reg_base + SNB_SBAR5XLAT_OFFSET; + ndev->limits.max_spads = SNB_MAX_B2B_SPADS; + + /* There is a Xeon hardware errata related to writes to + * SDOORBELL or B2BDOORBELL in conjunction with inbound access + * to NTB MMIO Space, which may hang the system. To workaround + * this use the second memory window to access the interrupt and + * scratch pad registers on the remote system. + */ + if (ndev->wa_flags & WA_SNB_ERR) { + if (!ndev->mw[ndev->limits.max_mw - 1].bar_sz) + return -EINVAL; + + ndev->limits.max_db_bits = SNB_MAX_DB_BITS; + ndev->reg_ofs.spad_write = + ndev->mw[ndev->limits.max_mw - 1].vbase + + SNB_SPAD_OFFSET; + ndev->reg_ofs.rdb = + ndev->mw[ndev->limits.max_mw - 1].vbase + + SNB_PDOORBELL_OFFSET; + + /* Set the Limit register to 4k, the minimum size, to + * prevent an illegal access + */ + writeq(ndev->mw[1].bar_sz + 0x1000, ndev->reg_base + + SNB_PBAR4LMT_OFFSET); + /* HW errata on the Limit registers. They can only be + * written when the base register is 4GB aligned and + * < 32bit. This should already be the case based on + * the driver defaults, but write the Limit registers + * first just in case. + */ + + ndev->limits.max_mw = SNB_ERRATA_MAX_MW; + } else { + /* HW Errata on bit 14 of b2bdoorbell register. Writes + * will not be mirrored to the remote system. Shrink + * the number of bits by one, since bit 14 is the last + * bit. + */ + ndev->limits.max_db_bits = SNB_MAX_DB_BITS - 1; + ndev->reg_ofs.spad_write = ndev->reg_base + + SNB_B2B_SPAD_OFFSET; + ndev->reg_ofs.rdb = ndev->reg_base + + SNB_B2B_DOORBELL_OFFSET; + + /* Disable the Limit register, just incase it is set to + * something silly. A 64bit write should handle it + * regardless of whether it has a split BAR or not. + */ + writeq(0, ndev->reg_base + SNB_PBAR4LMT_OFFSET); + /* HW errata on the Limit registers. They can only be + * written when the base register is 4GB aligned and + * < 32bit. This should already be the case based on + * the driver defaults, but write the Limit registers + * first just in case. + */ + if (ndev->split_bar) + ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW; + else + ndev->limits.max_mw = SNB_MAX_MW; + } + + /* The Xeon errata workaround requires setting SBAR Base + * addresses to known values, so that the PBAR XLAT can be + * pointed at SBAR0 of the remote system. + */ + if (ndev->dev_type == NTB_DEV_USD) { + writeq(SNB_MBAR23_DSD_ADDR, ndev->reg_base + + SNB_PBAR2XLAT_OFFSET); + if (ndev->wa_flags & WA_SNB_ERR) + writeq(SNB_MBAR01_DSD_ADDR, ndev->reg_base + + SNB_PBAR4XLAT_OFFSET); + else { + if (ndev->split_bar) { + writel(SNB_MBAR4_DSD_ADDR, + ndev->reg_base + + SNB_PBAR4XLAT_OFFSET); + writel(SNB_MBAR5_DSD_ADDR, + ndev->reg_base + + SNB_PBAR5XLAT_OFFSET); + } else + writeq(SNB_MBAR4_DSD_ADDR, + ndev->reg_base + + SNB_PBAR4XLAT_OFFSET); + + /* B2B_XLAT_OFFSET is a 64bit register, but can + * only take 32bit writes + */ + writel(SNB_MBAR01_DSD_ADDR & 0xffffffff, + ndev->reg_base + SNB_B2B_XLAT_OFFSETL); + writel(SNB_MBAR01_DSD_ADDR >> 32, + ndev->reg_base + SNB_B2B_XLAT_OFFSETU); + } + + writeq(SNB_MBAR01_USD_ADDR, ndev->reg_base + + SNB_SBAR0BASE_OFFSET); + writeq(SNB_MBAR23_USD_ADDR, ndev->reg_base + + SNB_SBAR2BASE_OFFSET); + if (ndev->split_bar) { + writel(SNB_MBAR4_USD_ADDR, ndev->reg_base + + SNB_SBAR4BASE_OFFSET); + writel(SNB_MBAR5_USD_ADDR, ndev->reg_base + + SNB_SBAR5BASE_OFFSET); + } else + writeq(SNB_MBAR4_USD_ADDR, ndev->reg_base + + SNB_SBAR4BASE_OFFSET); + } else { + writeq(SNB_MBAR23_USD_ADDR, ndev->reg_base + + SNB_PBAR2XLAT_OFFSET); + if (ndev->wa_flags & WA_SNB_ERR) + writeq(SNB_MBAR01_USD_ADDR, ndev->reg_base + + SNB_PBAR4XLAT_OFFSET); + else { + if (ndev->split_bar) { + writel(SNB_MBAR4_USD_ADDR, + ndev->reg_base + + SNB_PBAR4XLAT_OFFSET); + writel(SNB_MBAR5_USD_ADDR, + ndev->reg_base + + SNB_PBAR5XLAT_OFFSET); + } else + writeq(SNB_MBAR4_USD_ADDR, + ndev->reg_base + + SNB_PBAR4XLAT_OFFSET); + + /* + * B2B_XLAT_OFFSET is a 64bit register, but can + * only take 32bit writes + */ + writel(SNB_MBAR01_USD_ADDR & 0xffffffff, + ndev->reg_base + SNB_B2B_XLAT_OFFSETL); + writel(SNB_MBAR01_USD_ADDR >> 32, + ndev->reg_base + SNB_B2B_XLAT_OFFSETU); + } + writeq(SNB_MBAR01_DSD_ADDR, ndev->reg_base + + SNB_SBAR0BASE_OFFSET); + writeq(SNB_MBAR23_DSD_ADDR, ndev->reg_base + + SNB_SBAR2BASE_OFFSET); + if (ndev->split_bar) { + writel(SNB_MBAR4_DSD_ADDR, ndev->reg_base + + SNB_SBAR4BASE_OFFSET); + writel(SNB_MBAR5_DSD_ADDR, ndev->reg_base + + SNB_SBAR5BASE_OFFSET); + } else + writeq(SNB_MBAR4_DSD_ADDR, ndev->reg_base + + SNB_SBAR4BASE_OFFSET); + + } + break; + case NTB_CONN_RP: + if (ndev->wa_flags & WA_SNB_ERR) { + dev_err(&ndev->pdev->dev, + "NTB-RP disabled due to hardware errata.\n"); + return -EINVAL; + } + + /* Scratch pads need to have exclusive access from the primary + * or secondary side. Halve the num spads so that each side can + * have an equal amount. + */ + ndev->limits.max_spads = SNB_MAX_COMPAT_SPADS / 2; + ndev->limits.max_db_bits = SNB_MAX_DB_BITS; + /* Note: The SDOORBELL is the cause of the errata. You REALLY + * don't want to touch it. + */ + ndev->reg_ofs.rdb = ndev->reg_base + SNB_SDOORBELL_OFFSET; + ndev->reg_ofs.ldb = ndev->reg_base + SNB_PDOORBELL_OFFSET; + ndev->reg_ofs.ldb_mask = ndev->reg_base + SNB_PDBMSK_OFFSET; + /* Offset the start of the spads to correspond to whether it is + * primary or secondary + */ + ndev->reg_ofs.spad_write = ndev->reg_base + SNB_SPAD_OFFSET + + ndev->limits.max_spads * 4; + ndev->reg_ofs.spad_read = ndev->reg_base + SNB_SPAD_OFFSET; + ndev->reg_ofs.bar2_xlat = ndev->reg_base + SNB_SBAR2XLAT_OFFSET; + ndev->reg_ofs.bar4_xlat = ndev->reg_base + SNB_SBAR4XLAT_OFFSET; + if (ndev->split_bar) { + ndev->reg_ofs.bar5_xlat = + ndev->reg_base + SNB_SBAR5XLAT_OFFSET; + ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW; + } else + ndev->limits.max_mw = SNB_MAX_MW; + break; + case NTB_CONN_TRANSPARENT: + if (ndev->wa_flags & WA_SNB_ERR) { + dev_err(&ndev->pdev->dev, + "NTB-TRANSPARENT disabled due to hardware errata.\n"); + return -EINVAL; + } + + /* Scratch pads need to have exclusive access from the primary + * or secondary side. Halve the num spads so that each side can + * have an equal amount. + */ + ndev->limits.max_spads = SNB_MAX_COMPAT_SPADS / 2; + ndev->limits.max_db_bits = SNB_MAX_DB_BITS; + ndev->reg_ofs.rdb = ndev->reg_base + SNB_PDOORBELL_OFFSET; + ndev->reg_ofs.ldb = ndev->reg_base + SNB_SDOORBELL_OFFSET; + ndev->reg_ofs.ldb_mask = ndev->reg_base + SNB_SDBMSK_OFFSET; + ndev->reg_ofs.spad_write = ndev->reg_base + SNB_SPAD_OFFSET; + /* Offset the start of the spads to correspond to whether it is + * primary or secondary + */ + ndev->reg_ofs.spad_read = ndev->reg_base + SNB_SPAD_OFFSET + + ndev->limits.max_spads * 4; + ndev->reg_ofs.bar2_xlat = ndev->reg_base + SNB_PBAR2XLAT_OFFSET; + ndev->reg_ofs.bar4_xlat = ndev->reg_base + SNB_PBAR4XLAT_OFFSET; + + if (ndev->split_bar) { + ndev->reg_ofs.bar5_xlat = + ndev->reg_base + SNB_PBAR5XLAT_OFFSET; + ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW; + } else + ndev->limits.max_mw = SNB_MAX_MW; + break; + default: + /* + * we should never hit this. the detect function should've + * take cared of everything. + */ + return -EINVAL; + } + + ndev->reg_ofs.lnk_cntl = ndev->reg_base + SNB_NTBCNTL_OFFSET; + ndev->reg_ofs.lnk_stat = ndev->reg_base + SNB_SLINK_STATUS_OFFSET; + ndev->reg_ofs.spci_cmd = ndev->reg_base + SNB_PCICMD_OFFSET; + + ndev->limits.msix_cnt = SNB_MSIX_CNT; + ndev->bits_per_vector = SNB_DB_BITS_PER_VEC; + + return 0; +} + +static int ntb_bwd_setup(struct ntb_device *ndev) +{ + int rc; + u32 val; + + ndev->hw_type = BWD_HW; + + rc = pci_read_config_dword(ndev->pdev, NTB_PPD_OFFSET, &val); + if (rc) + return rc; + + switch ((val & BWD_PPD_CONN_TYPE) >> 8) { + case NTB_CONN_B2B: + ndev->conn_type = NTB_CONN_B2B; + break; + case NTB_CONN_RP: + default: + dev_err(&ndev->pdev->dev, "Unsupported NTB configuration\n"); + return -EINVAL; + } + + if (val & BWD_PPD_DEV_TYPE) + ndev->dev_type = NTB_DEV_DSD; + else + ndev->dev_type = NTB_DEV_USD; + + /* Initiate PCI-E link training */ + rc = pci_write_config_dword(ndev->pdev, NTB_PPD_OFFSET, + val | BWD_PPD_INIT_LINK); + if (rc) + return rc; + + ndev->reg_ofs.ldb = ndev->reg_base + BWD_PDOORBELL_OFFSET; + ndev->reg_ofs.ldb_mask = ndev->reg_base + BWD_PDBMSK_OFFSET; + ndev->reg_ofs.rdb = ndev->reg_base + BWD_B2B_DOORBELL_OFFSET; + ndev->reg_ofs.bar2_xlat = ndev->reg_base + BWD_SBAR2XLAT_OFFSET; + ndev->reg_ofs.bar4_xlat = ndev->reg_base + BWD_SBAR4XLAT_OFFSET; + ndev->reg_ofs.lnk_cntl = ndev->reg_base + BWD_NTBCNTL_OFFSET; + ndev->reg_ofs.lnk_stat = ndev->reg_base + BWD_LINK_STATUS_OFFSET; + ndev->reg_ofs.spad_read = ndev->reg_base + BWD_SPAD_OFFSET; + ndev->reg_ofs.spad_write = ndev->reg_base + BWD_B2B_SPAD_OFFSET; + ndev->reg_ofs.spci_cmd = ndev->reg_base + BWD_PCICMD_OFFSET; + ndev->limits.max_mw = BWD_MAX_MW; + ndev->limits.max_spads = BWD_MAX_SPADS; + ndev->limits.max_db_bits = BWD_MAX_DB_BITS; + ndev->limits.msix_cnt = BWD_MSIX_CNT; + ndev->bits_per_vector = BWD_DB_BITS_PER_VEC; + + /* Since bwd doesn't have a link interrupt, setup a poll timer */ + INIT_DELAYED_WORK(&ndev->hb_timer, bwd_link_poll); + INIT_DELAYED_WORK(&ndev->lr_timer, bwd_link_recovery); + schedule_delayed_work(&ndev->hb_timer, NTB_HB_TIMEOUT); + + return 0; +} + +static int ntb_device_setup(struct ntb_device *ndev) +{ + int rc; + + if (is_ntb_xeon(ndev)) + rc = ntb_xeon_setup(ndev); + else if (is_ntb_atom(ndev)) + rc = ntb_bwd_setup(ndev); + else + rc = -ENODEV; + + if (rc) + return rc; + + if (ndev->conn_type == NTB_CONN_B2B) + /* Enable Bus Master and Memory Space on the secondary side */ + writew(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER, + ndev->reg_ofs.spci_cmd); + + return 0; +} + +static void ntb_device_free(struct ntb_device *ndev) +{ + if (is_ntb_atom(ndev)) { + cancel_delayed_work_sync(&ndev->hb_timer); + cancel_delayed_work_sync(&ndev->lr_timer); + } +} + +static irqreturn_t bwd_callback_msix_irq(int irq, void *data) +{ + struct ntb_db_cb *db_cb = data; + struct ntb_device *ndev = db_cb->ndev; + unsigned long mask; + + dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for DB %d\n", irq, + db_cb->db_num); + + mask = readw(ndev->reg_ofs.ldb_mask); + set_bit(db_cb->db_num * ndev->bits_per_vector, &mask); + writew(mask, ndev->reg_ofs.ldb_mask); + + tasklet_schedule(&db_cb->irq_work); + + /* No need to check for the specific HB irq, any interrupt means + * we're connected. + */ + ndev->last_ts = jiffies; + + writeq((u64) 1 << db_cb->db_num, ndev->reg_ofs.ldb); + + return IRQ_HANDLED; +} + +static irqreturn_t xeon_callback_msix_irq(int irq, void *data) +{ + struct ntb_db_cb *db_cb = data; + struct ntb_device *ndev = db_cb->ndev; + unsigned long mask; + + dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for DB %d\n", irq, + db_cb->db_num); + + mask = readw(ndev->reg_ofs.ldb_mask); + set_bit(db_cb->db_num * ndev->bits_per_vector, &mask); + writew(mask, ndev->reg_ofs.ldb_mask); + + tasklet_schedule(&db_cb->irq_work); + + /* On Sandybridge, there are 16 bits in the interrupt register + * but only 4 vectors. So, 5 bits are assigned to the first 3 + * vectors, with the 4th having a single bit for link + * interrupts. + */ + writew(((1 << ndev->bits_per_vector) - 1) << + (db_cb->db_num * ndev->bits_per_vector), ndev->reg_ofs.ldb); + + return IRQ_HANDLED; +} + +/* Since we do not have a HW doorbell in BWD, this is only used in JF/JT */ +static irqreturn_t xeon_event_msix_irq(int irq, void *dev) +{ + struct ntb_device *ndev = dev; + int rc; + + dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for Events\n", irq); + + rc = ntb_link_status(ndev); + if (rc) + dev_err(&ndev->pdev->dev, "Error determining link status\n"); + + /* bit 15 is always the link bit */ + writew(1 << SNB_LINK_DB, ndev->reg_ofs.ldb); + + return IRQ_HANDLED; +} + +static irqreturn_t ntb_interrupt(int irq, void *dev) +{ + struct ntb_device *ndev = dev; + unsigned int i = 0; + + if (is_ntb_atom(ndev)) { + u64 ldb = readq(ndev->reg_ofs.ldb); + + dev_dbg(&ndev->pdev->dev, "irq %d - ldb = %Lx\n", irq, ldb); + + while (ldb) { + i = __ffs(ldb); + ldb &= ldb - 1; + bwd_callback_msix_irq(irq, &ndev->db_cb[i]); + } + } else { + u16 ldb = readw(ndev->reg_ofs.ldb); + + dev_dbg(&ndev->pdev->dev, "irq %d - ldb = %x\n", irq, ldb); + + if (ldb & SNB_DB_HW_LINK) { + xeon_event_msix_irq(irq, dev); + ldb &= ~SNB_DB_HW_LINK; + } + + while (ldb) { + i = __ffs(ldb); + ldb &= ldb - 1; + xeon_callback_msix_irq(irq, &ndev->db_cb[i]); + } + } + + return IRQ_HANDLED; +} + +static int ntb_setup_snb_msix(struct ntb_device *ndev, int msix_entries) +{ + struct pci_dev *pdev = ndev->pdev; + struct msix_entry *msix; + int rc, i; + + if (msix_entries < ndev->limits.msix_cnt) + return -ENOSPC; + + rc = pci_enable_msix_exact(pdev, ndev->msix_entries, msix_entries); + if (rc < 0) + return rc; + + for (i = 0; i < msix_entries; i++) { + msix = &ndev->msix_entries[i]; + WARN_ON(!msix->vector); + + if (i == msix_entries - 1) { + rc = request_irq(msix->vector, + xeon_event_msix_irq, 0, + "ntb-event-msix", ndev); + if (rc) + goto err; + } else { + rc = request_irq(msix->vector, + xeon_callback_msix_irq, 0, + "ntb-callback-msix", + &ndev->db_cb[i]); + if (rc) + goto err; + } + } + + ndev->num_msix = msix_entries; + ndev->max_cbs = msix_entries - 1; + + return 0; + +err: + while (--i >= 0) { + /* Code never reaches here for entry nr 'ndev->num_msix - 1' */ + msix = &ndev->msix_entries[i]; + free_irq(msix->vector, &ndev->db_cb[i]); + } + + pci_disable_msix(pdev); + ndev->num_msix = 0; + + return rc; +} + +static int ntb_setup_bwd_msix(struct ntb_device *ndev, int msix_entries) +{ + struct pci_dev *pdev = ndev->pdev; + struct msix_entry *msix; + int rc, i; + + msix_entries = pci_enable_msix_range(pdev, ndev->msix_entries, + 1, msix_entries); + if (msix_entries < 0) + return msix_entries; + + for (i = 0; i < msix_entries; i++) { + msix = &ndev->msix_entries[i]; + WARN_ON(!msix->vector); + + rc = request_irq(msix->vector, bwd_callback_msix_irq, 0, + "ntb-callback-msix", &ndev->db_cb[i]); + if (rc) + goto err; + } + + ndev->num_msix = msix_entries; + ndev->max_cbs = msix_entries; + + return 0; + +err: + while (--i >= 0) + free_irq(msix->vector, &ndev->db_cb[i]); + + pci_disable_msix(pdev); + ndev->num_msix = 0; + + return rc; +} + +static int ntb_setup_msix(struct ntb_device *ndev) +{ + struct pci_dev *pdev = ndev->pdev; + int msix_entries; + int rc, i; + + msix_entries = pci_msix_vec_count(pdev); + if (msix_entries < 0) { + rc = msix_entries; + goto err; + } else if (msix_entries > ndev->limits.msix_cnt) { + rc = -EINVAL; + goto err; + } + + ndev->msix_entries = kmalloc(sizeof(struct msix_entry) * msix_entries, + GFP_KERNEL); + if (!ndev->msix_entries) { + rc = -ENOMEM; + goto err; + } + + for (i = 0; i < msix_entries; i++) + ndev->msix_entries[i].entry = i; + + if (is_ntb_atom(ndev)) + rc = ntb_setup_bwd_msix(ndev, msix_entries); + else + rc = ntb_setup_snb_msix(ndev, msix_entries); + if (rc) + goto err1; + + return 0; + +err1: + kfree(ndev->msix_entries); +err: + dev_err(&pdev->dev, "Error allocating MSI-X interrupt\n"); + return rc; +} + +static int ntb_setup_msi(struct ntb_device *ndev) +{ + struct pci_dev *pdev = ndev->pdev; + int rc; + + rc = pci_enable_msi(pdev); + if (rc) + return rc; + + rc = request_irq(pdev->irq, ntb_interrupt, 0, "ntb-msi", ndev); + if (rc) { + pci_disable_msi(pdev); + dev_err(&pdev->dev, "Error allocating MSI interrupt\n"); + return rc; + } + + return 0; +} + +static int ntb_setup_intx(struct ntb_device *ndev) +{ + struct pci_dev *pdev = ndev->pdev; + int rc; + + /* Verify intx is enabled */ + pci_intx(pdev, 1); + + rc = request_irq(pdev->irq, ntb_interrupt, IRQF_SHARED, "ntb-intx", + ndev); + if (rc) + return rc; + + return 0; +} + +static int ntb_setup_interrupts(struct ntb_device *ndev) +{ + int rc; + + /* On BWD, disable all interrupts. On SNB, disable all but Link + * Interrupt. The rest will be unmasked as callbacks are registered. + */ + if (is_ntb_atom(ndev)) + writeq(~0, ndev->reg_ofs.ldb_mask); + else { + u16 var = 1 << SNB_LINK_DB; + writew(~var, ndev->reg_ofs.ldb_mask); + } + + rc = ntb_setup_msix(ndev); + if (!rc) + goto done; + + ndev->bits_per_vector = 1; + ndev->max_cbs = ndev->limits.max_db_bits; + + rc = ntb_setup_msi(ndev); + if (!rc) + goto done; + + rc = ntb_setup_intx(ndev); + if (rc) { + dev_err(&ndev->pdev->dev, "no usable interrupts\n"); + return rc; + } + +done: + return 0; +} + +static void ntb_free_interrupts(struct ntb_device *ndev) +{ + struct pci_dev *pdev = ndev->pdev; + + /* mask interrupts */ + if (is_ntb_atom(ndev)) + writeq(~0, ndev->reg_ofs.ldb_mask); + else + writew(~0, ndev->reg_ofs.ldb_mask); + + if (ndev->num_msix) { + struct msix_entry *msix; + u32 i; + + for (i = 0; i < ndev->num_msix; i++) { + msix = &ndev->msix_entries[i]; + if (is_ntb_xeon(ndev) && i == ndev->num_msix - 1) + free_irq(msix->vector, ndev); + else + free_irq(msix->vector, &ndev->db_cb[i]); + } + pci_disable_msix(pdev); + kfree(ndev->msix_entries); + } else { + free_irq(pdev->irq, ndev); + + if (pci_dev_msi_enabled(pdev)) + pci_disable_msi(pdev); + } +} + +static int ntb_create_callbacks(struct ntb_device *ndev) +{ + int i; + + /* Chicken-egg issue. We won't know how many callbacks are necessary + * until we see how many MSI-X vectors we get, but these pointers need + * to be passed into the MSI-X register function. So, we allocate the + * max, knowing that they might not all be used, to work around this. + */ + ndev->db_cb = kcalloc(ndev->limits.max_db_bits, + sizeof(struct ntb_db_cb), + GFP_KERNEL); + if (!ndev->db_cb) + return -ENOMEM; + + for (i = 0; i < ndev->limits.max_db_bits; i++) { + ndev->db_cb[i].db_num = i; + ndev->db_cb[i].ndev = ndev; + } + + return 0; +} + +static void ntb_free_callbacks(struct ntb_device *ndev) +{ + int i; + + for (i = 0; i < ndev->limits.max_db_bits; i++) + ntb_unregister_db_callback(ndev, i); + + kfree(ndev->db_cb); +} + +static ssize_t ntb_debugfs_read(struct file *filp, char __user *ubuf, + size_t count, loff_t *offp) +{ + struct ntb_device *ndev; + char *buf; + ssize_t ret, offset, out_count; + + out_count = 500; + + buf = kmalloc(out_count, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + ndev = filp->private_data; + offset = 0; + offset += snprintf(buf + offset, out_count - offset, + "NTB Device Information:\n"); + offset += snprintf(buf + offset, out_count - offset, + "Connection Type - \t\t%s\n", + ndev->conn_type == NTB_CONN_TRANSPARENT ? + "Transparent" : (ndev->conn_type == NTB_CONN_B2B) ? + "Back to back" : "Root Port"); + offset += snprintf(buf + offset, out_count - offset, + "Device Type - \t\t\t%s\n", + ndev->dev_type == NTB_DEV_USD ? + "DSD/USP" : "USD/DSP"); + offset += snprintf(buf + offset, out_count - offset, + "Max Number of Callbacks - \t%u\n", + ntb_max_cbs(ndev)); + offset += snprintf(buf + offset, out_count - offset, + "Link Status - \t\t\t%s\n", + ntb_hw_link_status(ndev) ? "Up" : "Down"); + if (ntb_hw_link_status(ndev)) { + offset += snprintf(buf + offset, out_count - offset, + "Link Speed - \t\t\tPCI-E Gen %u\n", + ndev->link_speed); + offset += snprintf(buf + offset, out_count - offset, + "Link Width - \t\t\tx%u\n", + ndev->link_width); + } + + if (is_ntb_xeon(ndev)) { + u32 status32; + u16 status16; + int rc; + + offset += snprintf(buf + offset, out_count - offset, + "\nNTB Device Statistics:\n"); + offset += snprintf(buf + offset, out_count - offset, + "Upstream Memory Miss - \t%u\n", + readw(ndev->reg_base + + SNB_USMEMMISS_OFFSET)); + + offset += snprintf(buf + offset, out_count - offset, + "\nNTB Hardware Errors:\n"); + + rc = pci_read_config_word(ndev->pdev, SNB_DEVSTS_OFFSET, + &status16); + if (!rc) + offset += snprintf(buf + offset, out_count - offset, + "DEVSTS - \t%#06x\n", status16); + + rc = pci_read_config_word(ndev->pdev, SNB_LINK_STATUS_OFFSET, + &status16); + if (!rc) + offset += snprintf(buf + offset, out_count - offset, + "LNKSTS - \t%#06x\n", status16); + + rc = pci_read_config_dword(ndev->pdev, SNB_UNCERRSTS_OFFSET, + &status32); + if (!rc) + offset += snprintf(buf + offset, out_count - offset, + "UNCERRSTS - \t%#010x\n", status32); + + rc = pci_read_config_dword(ndev->pdev, SNB_CORERRSTS_OFFSET, + &status32); + if (!rc) + offset += snprintf(buf + offset, out_count - offset, + "CORERRSTS - \t%#010x\n", status32); + } + + if (offset > out_count) + offset = out_count; + + ret = simple_read_from_buffer(ubuf, count, offp, buf, offset); + kfree(buf); + return ret; +} + +static const struct file_operations ntb_debugfs_info = { + .owner = THIS_MODULE, + .open = simple_open, + .read = ntb_debugfs_read, +}; + +static void ntb_setup_debugfs(struct ntb_device *ndev) +{ + if (!debugfs_initialized()) + return; + + if (!debugfs_dir) + debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL); + + ndev->debugfs_dir = debugfs_create_dir(pci_name(ndev->pdev), + debugfs_dir); + if (ndev->debugfs_dir) + ndev->debugfs_info = debugfs_create_file("info", S_IRUSR, + ndev->debugfs_dir, + ndev, + &ntb_debugfs_info); +} + +static void ntb_free_debugfs(struct ntb_device *ndev) +{ + debugfs_remove_recursive(ndev->debugfs_dir); + + if (debugfs_dir && simple_empty(debugfs_dir)) { + debugfs_remove_recursive(debugfs_dir); + debugfs_dir = NULL; + } +} + +static void ntb_hw_link_up(struct ntb_device *ndev) +{ + if (ndev->conn_type == NTB_CONN_TRANSPARENT) + ntb_link_event(ndev, NTB_LINK_UP); + else { + u32 ntb_cntl; + + /* Let's bring the NTB link up */ + ntb_cntl = readl(ndev->reg_ofs.lnk_cntl); + ntb_cntl &= ~(NTB_CNTL_LINK_DISABLE | NTB_CNTL_CFG_LOCK); + ntb_cntl |= NTB_CNTL_P2S_BAR23_SNOOP | NTB_CNTL_S2P_BAR23_SNOOP; + ntb_cntl |= NTB_CNTL_P2S_BAR4_SNOOP | NTB_CNTL_S2P_BAR4_SNOOP; + if (ndev->split_bar) + ntb_cntl |= NTB_CNTL_P2S_BAR5_SNOOP | + NTB_CNTL_S2P_BAR5_SNOOP; + + writel(ntb_cntl, ndev->reg_ofs.lnk_cntl); + } +} + +static void ntb_hw_link_down(struct ntb_device *ndev) +{ + u32 ntb_cntl; + + if (ndev->conn_type == NTB_CONN_TRANSPARENT) { + ntb_link_event(ndev, NTB_LINK_DOWN); + return; + } + + /* Bring NTB link down */ + ntb_cntl = readl(ndev->reg_ofs.lnk_cntl); + ntb_cntl &= ~(NTB_CNTL_P2S_BAR23_SNOOP | NTB_CNTL_S2P_BAR23_SNOOP); + ntb_cntl &= ~(NTB_CNTL_P2S_BAR4_SNOOP | NTB_CNTL_S2P_BAR4_SNOOP); + if (ndev->split_bar) + ntb_cntl &= ~(NTB_CNTL_P2S_BAR5_SNOOP | + NTB_CNTL_S2P_BAR5_SNOOP); + ntb_cntl |= NTB_CNTL_LINK_DISABLE | NTB_CNTL_CFG_LOCK; + writel(ntb_cntl, ndev->reg_ofs.lnk_cntl); +} + +static void ntb_max_mw_detect(struct ntb_device *ndev) +{ + if (ndev->split_bar) + ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW; + else + ndev->limits.max_mw = SNB_MAX_MW; +} + +static int ntb_xeon_detect(struct ntb_device *ndev) +{ + int rc, bars_mask; + u32 bars; + u8 ppd; + + ndev->hw_type = SNB_HW; + + rc = pci_read_config_byte(ndev->pdev, NTB_PPD_OFFSET, &ppd); + if (rc) + return -EIO; + + if (ppd & SNB_PPD_DEV_TYPE) + ndev->dev_type = NTB_DEV_USD; + else + ndev->dev_type = NTB_DEV_DSD; + + ndev->split_bar = (ppd & SNB_PPD_SPLIT_BAR) ? 1 : 0; + + switch (ppd & SNB_PPD_CONN_TYPE) { + case NTB_CONN_B2B: + dev_info(&ndev->pdev->dev, "Conn Type = B2B\n"); + ndev->conn_type = NTB_CONN_B2B; + break; + case NTB_CONN_RP: + dev_info(&ndev->pdev->dev, "Conn Type = RP\n"); + ndev->conn_type = NTB_CONN_RP; + break; + case NTB_CONN_TRANSPARENT: + dev_info(&ndev->pdev->dev, "Conn Type = TRANSPARENT\n"); + ndev->conn_type = NTB_CONN_TRANSPARENT; + /* + * This mode is default to USD/DSP. HW does not report + * properly in transparent mode as it has no knowledge of + * NTB. We will just force correct here. + */ + ndev->dev_type = NTB_DEV_USD; + + /* + * This is a way for transparent BAR to figure out if we + * are doing split BAR or not. There is no way for the hw + * on the transparent side to know and set the PPD. + */ + bars_mask = pci_select_bars(ndev->pdev, IORESOURCE_MEM); + bars = hweight32(bars_mask); + if (bars == (HSX_SPLITBAR_MAX_MW + 1)) + ndev->split_bar = 1; + + break; + default: + dev_err(&ndev->pdev->dev, "Unknown PPD %x\n", ppd); + return -ENODEV; + } + + ntb_max_mw_detect(ndev); + + return 0; +} + +static int ntb_atom_detect(struct ntb_device *ndev) +{ + int rc; + u32 ppd; + + ndev->hw_type = BWD_HW; + ndev->limits.max_mw = BWD_MAX_MW; + + rc = pci_read_config_dword(ndev->pdev, NTB_PPD_OFFSET, &ppd); + if (rc) + return rc; + + switch ((ppd & BWD_PPD_CONN_TYPE) >> 8) { + case NTB_CONN_B2B: + dev_info(&ndev->pdev->dev, "Conn Type = B2B\n"); + ndev->conn_type = NTB_CONN_B2B; + break; + case NTB_CONN_RP: + default: + dev_err(&ndev->pdev->dev, "Unsupported NTB configuration\n"); + return -EINVAL; + } + + if (ppd & BWD_PPD_DEV_TYPE) + ndev->dev_type = NTB_DEV_DSD; + else + ndev->dev_type = NTB_DEV_USD; + + return 0; +} + +static int ntb_device_detect(struct ntb_device *ndev) +{ + int rc; + + if (is_ntb_xeon(ndev)) + rc = ntb_xeon_detect(ndev); + else if (is_ntb_atom(ndev)) + rc = ntb_atom_detect(ndev); + else + rc = -ENODEV; + + dev_info(&ndev->pdev->dev, "Device Type = %s\n", + ndev->dev_type == NTB_DEV_USD ? "USD/DSP" : "DSD/USP"); + + return 0; +} + +static int ntb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct ntb_device *ndev; + int rc, i; + + ndev = kzalloc(sizeof(struct ntb_device), GFP_KERNEL); + if (!ndev) + return -ENOMEM; + + ndev->pdev = pdev; + + ntb_set_errata_flags(ndev); + + ndev->link_status = NTB_LINK_DOWN; + pci_set_drvdata(pdev, ndev); + ntb_setup_debugfs(ndev); + + rc = pci_enable_device(pdev); + if (rc) + goto err; + + pci_set_master(ndev->pdev); + + rc = ntb_device_detect(ndev); + if (rc) + goto err; + + ndev->mw = kcalloc(ndev->limits.max_mw, sizeof(struct ntb_mw), + GFP_KERNEL); + if (!ndev->mw) { + rc = -ENOMEM; + goto err1; + } + + if (ndev->split_bar) + rc = pci_request_selected_regions(pdev, NTB_SPLITBAR_MASK, + KBUILD_MODNAME); + else + rc = pci_request_selected_regions(pdev, NTB_BAR_MASK, + KBUILD_MODNAME); + + if (rc) + goto err2; + + ndev->reg_base = pci_ioremap_bar(pdev, NTB_BAR_MMIO); + if (!ndev->reg_base) { + dev_warn(&pdev->dev, "Cannot remap BAR 0\n"); + rc = -EIO; + goto err3; + } + + for (i = 0; i < ndev->limits.max_mw; i++) { + ndev->mw[i].bar_sz = pci_resource_len(pdev, MW_TO_BAR(i)); + + /* + * with the errata we need to steal last of the memory + * windows for workarounds and they point to MMIO registers. + */ + if ((ndev->wa_flags & WA_SNB_ERR) && + (i == (ndev->limits.max_mw - 1))) { + ndev->mw[i].vbase = + ioremap_nocache(pci_resource_start(pdev, + MW_TO_BAR(i)), + ndev->mw[i].bar_sz); + } else { + ndev->mw[i].vbase = + ioremap_wc(pci_resource_start(pdev, + MW_TO_BAR(i)), + ndev->mw[i].bar_sz); + } + + dev_info(&pdev->dev, "MW %d size %llu\n", i, + (unsigned long long) ndev->mw[i].bar_sz); + if (!ndev->mw[i].vbase) { + dev_warn(&pdev->dev, "Cannot remap BAR %d\n", + MW_TO_BAR(i)); + rc = -EIO; + goto err4; + } + } + + rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); + if (rc) { + rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (rc) + goto err4; + + dev_warn(&pdev->dev, "Cannot DMA highmem\n"); + } + + rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); + if (rc) { + rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + if (rc) + goto err4; + + dev_warn(&pdev->dev, "Cannot DMA consistent highmem\n"); + } + + rc = ntb_device_setup(ndev); + if (rc) + goto err4; + + rc = ntb_create_callbacks(ndev); + if (rc) + goto err5; + + rc = ntb_setup_interrupts(ndev); + if (rc) + goto err6; + + /* The scratchpad registers keep the values between rmmod/insmod, + * blast them now + */ + for (i = 0; i < ndev->limits.max_spads; i++) { + ntb_write_local_spad(ndev, i, 0); + ntb_write_remote_spad(ndev, i, 0); + } + + rc = ntb_transport_init(pdev); + if (rc) + goto err7; + + ntb_hw_link_up(ndev); + + return 0; + +err7: + ntb_free_interrupts(ndev); +err6: + ntb_free_callbacks(ndev); +err5: + ntb_device_free(ndev); +err4: + for (i--; i >= 0; i--) + iounmap(ndev->mw[i].vbase); + iounmap(ndev->reg_base); +err3: + if (ndev->split_bar) + pci_release_selected_regions(pdev, NTB_SPLITBAR_MASK); + else + pci_release_selected_regions(pdev, NTB_BAR_MASK); +err2: + kfree(ndev->mw); +err1: + pci_disable_device(pdev); +err: + ntb_free_debugfs(ndev); + kfree(ndev); + + dev_err(&pdev->dev, "Error loading %s module\n", KBUILD_MODNAME); + return rc; +} + +static void ntb_pci_remove(struct pci_dev *pdev) +{ + struct ntb_device *ndev = pci_get_drvdata(pdev); + int i; + + ntb_hw_link_down(ndev); + + ntb_transport_free(ndev->ntb_transport); + + ntb_free_interrupts(ndev); + ntb_free_callbacks(ndev); + ntb_device_free(ndev); + + /* need to reset max_mw limits so we can unmap properly */ + if (ndev->hw_type == SNB_HW) + ntb_max_mw_detect(ndev); + + for (i = 0; i < ndev->limits.max_mw; i++) + iounmap(ndev->mw[i].vbase); + + kfree(ndev->mw); + iounmap(ndev->reg_base); + if (ndev->split_bar) + pci_release_selected_regions(pdev, NTB_SPLITBAR_MASK); + else + pci_release_selected_regions(pdev, NTB_BAR_MASK); + pci_disable_device(pdev); + ntb_free_debugfs(ndev); + kfree(ndev); +} + +static struct pci_driver ntb_pci_driver = { + .name = KBUILD_MODNAME, + .id_table = ntb_pci_tbl, + .probe = ntb_pci_probe, + .remove = ntb_pci_remove, +}; + +module_pci_driver(ntb_pci_driver); diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.h b/drivers/ntb/hw/intel/ntb_hw_intel.h new file mode 100644 index 000000000000..935610454f70 --- /dev/null +++ b/drivers/ntb/hw/intel/ntb_hw_intel.h @@ -0,0 +1,385 @@ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2012 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * BSD LICENSE + * + * Copyright(c) 2012 Intel Corporation. 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 copy + * 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. + * + * Intel PCIe NTB Linux driver + * + * Contact Information: + * Jon Mason + */ +#include + +#define NTB_LINK_STATUS_ACTIVE 0x2000 +#define NTB_LINK_SPEED_MASK 0x000f +#define NTB_LINK_WIDTH_MASK 0x03f0 + +#define SNB_MSIX_CNT 4 +#define SNB_MAX_B2B_SPADS 16 +#define SNB_MAX_COMPAT_SPADS 16 +/* Reserve the uppermost bit for link interrupt */ +#define SNB_MAX_DB_BITS 15 +#define SNB_LINK_DB 15 +#define SNB_DB_BITS_PER_VEC 5 +#define HSX_SPLITBAR_MAX_MW 3 +#define SNB_MAX_MW 2 +#define SNB_ERRATA_MAX_MW 1 + +#define SNB_DB_HW_LINK 0x8000 + +#define SNB_UNCERRSTS_OFFSET 0x014C +#define SNB_CORERRSTS_OFFSET 0x0158 +#define SNB_LINK_STATUS_OFFSET 0x01A2 +#define SNB_PCICMD_OFFSET 0x0504 +#define SNB_DEVCTRL_OFFSET 0x0598 +#define SNB_DEVSTS_OFFSET 0x059A +#define SNB_SLINK_STATUS_OFFSET 0x05A2 + +#define SNB_PBAR2LMT_OFFSET 0x0000 +#define SNB_PBAR4LMT_OFFSET 0x0008 +#define SNB_PBAR5LMT_OFFSET 0x000C +#define SNB_PBAR2XLAT_OFFSET 0x0010 +#define SNB_PBAR4XLAT_OFFSET 0x0018 +#define SNB_PBAR5XLAT_OFFSET 0x001C +#define SNB_SBAR2LMT_OFFSET 0x0020 +#define SNB_SBAR4LMT_OFFSET 0x0028 +#define SNB_SBAR5LMT_OFFSET 0x002C +#define SNB_SBAR2XLAT_OFFSET 0x0030 +#define SNB_SBAR4XLAT_OFFSET 0x0038 +#define SNB_SBAR5XLAT_OFFSET 0x003C +#define SNB_SBAR0BASE_OFFSET 0x0040 +#define SNB_SBAR2BASE_OFFSET 0x0048 +#define SNB_SBAR4BASE_OFFSET 0x0050 +#define SNB_SBAR5BASE_OFFSET 0x0054 +#define SNB_NTBCNTL_OFFSET 0x0058 +#define SNB_SBDF_OFFSET 0x005C +#define SNB_PDOORBELL_OFFSET 0x0060 +#define SNB_PDBMSK_OFFSET 0x0062 +#define SNB_SDOORBELL_OFFSET 0x0064 +#define SNB_SDBMSK_OFFSET 0x0066 +#define SNB_USMEMMISS_OFFSET 0x0070 +#define SNB_SPAD_OFFSET 0x0080 +#define SNB_SPADSEMA4_OFFSET 0x00c0 +#define SNB_WCCNTRL_OFFSET 0x00e0 +#define SNB_B2B_SPAD_OFFSET 0x0100 +#define SNB_B2B_DOORBELL_OFFSET 0x0140 +#define SNB_B2B_XLAT_OFFSETL 0x0144 +#define SNB_B2B_XLAT_OFFSETU 0x0148 + +/* + * The addresses are setup so the 32bit BARs can function. Thus + * the addresses are all in 32bit space + */ +#define SNB_MBAR01_USD_ADDR 0x000000002100000CULL +#define SNB_MBAR23_USD_ADDR 0x000000004100000CULL +#define SNB_MBAR4_USD_ADDR 0x000000008100000CULL +#define SNB_MBAR5_USD_ADDR 0x00000000A100000CULL +#define SNB_MBAR01_DSD_ADDR 0x000000002000000CULL +#define SNB_MBAR23_DSD_ADDR 0x000000004000000CULL +#define SNB_MBAR4_DSD_ADDR 0x000000008000000CULL +#define SNB_MBAR5_DSD_ADDR 0x00000000A000000CULL + +#define BWD_MSIX_CNT 34 +#define BWD_MAX_SPADS 16 +#define BWD_MAX_DB_BITS 34 +#define BWD_DB_BITS_PER_VEC 1 +#define BWD_MAX_MW 2 + +#define BWD_PCICMD_OFFSET 0xb004 +#define BWD_MBAR23_OFFSET 0xb018 +#define BWD_MBAR45_OFFSET 0xb020 +#define BWD_DEVCTRL_OFFSET 0xb048 +#define BWD_LINK_STATUS_OFFSET 0xb052 +#define BWD_ERRCORSTS_OFFSET 0xb110 + +#define BWD_SBAR2XLAT_OFFSET 0x0008 +#define BWD_SBAR4XLAT_OFFSET 0x0010 +#define BWD_PDOORBELL_OFFSET 0x0020 +#define BWD_PDBMSK_OFFSET 0x0028 +#define BWD_NTBCNTL_OFFSET 0x0060 +#define BWD_EBDF_OFFSET 0x0064 +#define BWD_SPAD_OFFSET 0x0080 +#define BWD_SPADSEMA_OFFSET 0x00c0 +#define BWD_STKYSPAD_OFFSET 0x00c4 +#define BWD_PBAR2XLAT_OFFSET 0x8008 +#define BWD_PBAR4XLAT_OFFSET 0x8010 +#define BWD_B2B_DOORBELL_OFFSET 0x8020 +#define BWD_B2B_SPAD_OFFSET 0x8080 +#define BWD_B2B_SPADSEMA_OFFSET 0x80c0 +#define BWD_B2B_STKYSPAD_OFFSET 0x80c4 + +#define BWD_MODPHY_PCSREG4 0x1c004 +#define BWD_MODPHY_PCSREG6 0x1c006 + +#define BWD_IP_BASE 0xC000 +#define BWD_DESKEWSTS_OFFSET (BWD_IP_BASE + 0x3024) +#define BWD_LTSSMERRSTS0_OFFSET (BWD_IP_BASE + 0x3180) +#define BWD_LTSSMSTATEJMP_OFFSET (BWD_IP_BASE + 0x3040) +#define BWD_IBSTERRRCRVSTS0_OFFSET (BWD_IP_BASE + 0x3324) + +#define BWD_DESKEWSTS_DBERR (1 << 15) +#define BWD_LTSSMERRSTS0_UNEXPECTEDEI (1 << 20) +#define BWD_LTSSMSTATEJMP_FORCEDETECT (1 << 2) +#define BWD_IBIST_ERR_OFLOW 0x7FFF7FFF + +#define NTB_CNTL_CFG_LOCK (1 << 0) +#define NTB_CNTL_LINK_DISABLE (1 << 1) +#define NTB_CNTL_S2P_BAR23_SNOOP (1 << 2) +#define NTB_CNTL_P2S_BAR23_SNOOP (1 << 4) +#define NTB_CNTL_S2P_BAR4_SNOOP (1 << 6) +#define NTB_CNTL_P2S_BAR4_SNOOP (1 << 8) +#define NTB_CNTL_S2P_BAR5_SNOOP (1 << 12) +#define NTB_CNTL_P2S_BAR5_SNOOP (1 << 14) +#define BWD_CNTL_LINK_DOWN (1 << 16) + +#define NTB_PPD_OFFSET 0x00D4 +#define SNB_PPD_CONN_TYPE 0x0003 +#define SNB_PPD_DEV_TYPE 0x0010 +#define SNB_PPD_SPLIT_BAR (1 << 6) +#define BWD_PPD_INIT_LINK 0x0008 +#define BWD_PPD_CONN_TYPE 0x0300 +#define BWD_PPD_DEV_TYPE 0x1000 +#define PCI_DEVICE_ID_INTEL_NTB_B2B_JSF 0x3725 +#define PCI_DEVICE_ID_INTEL_NTB_PS_JSF 0x3726 +#define PCI_DEVICE_ID_INTEL_NTB_SS_JSF 0x3727 +#define PCI_DEVICE_ID_INTEL_NTB_B2B_SNB 0x3C0D +#define PCI_DEVICE_ID_INTEL_NTB_PS_SNB 0x3C0E +#define PCI_DEVICE_ID_INTEL_NTB_SS_SNB 0x3C0F +#define PCI_DEVICE_ID_INTEL_NTB_B2B_IVT 0x0E0D +#define PCI_DEVICE_ID_INTEL_NTB_PS_IVT 0x0E0E +#define PCI_DEVICE_ID_INTEL_NTB_SS_IVT 0x0E0F +#define PCI_DEVICE_ID_INTEL_NTB_B2B_HSX 0x2F0D +#define PCI_DEVICE_ID_INTEL_NTB_PS_HSX 0x2F0E +#define PCI_DEVICE_ID_INTEL_NTB_SS_HSX 0x2F0F +#define PCI_DEVICE_ID_INTEL_NTB_B2B_BWD 0x0C4E + +#ifndef readq +static inline u64 readq(void __iomem *addr) +{ + return readl(addr) | (((u64) readl(addr + 4)) << 32LL); +} +#endif + +#ifndef writeq +static inline void writeq(u64 val, void __iomem *addr) +{ + writel(val & 0xffffffff, addr); + writel(val >> 32, addr + 4); +} +#endif + +#define NTB_BAR_MMIO 0 +#define NTB_BAR_23 2 +#define NTB_BAR_4 4 +#define NTB_BAR_5 5 + +#define NTB_BAR_MASK ((1 << NTB_BAR_MMIO) | (1 << NTB_BAR_23) |\ + (1 << NTB_BAR_4)) +#define NTB_SPLITBAR_MASK ((1 << NTB_BAR_MMIO) | (1 << NTB_BAR_23) |\ + (1 << NTB_BAR_4) | (1 << NTB_BAR_5)) + +#define NTB_HB_TIMEOUT msecs_to_jiffies(1000) + +enum ntb_hw_event { + NTB_EVENT_SW_EVENT0 = 0, + NTB_EVENT_SW_EVENT1, + NTB_EVENT_SW_EVENT2, + NTB_EVENT_HW_ERROR, + NTB_EVENT_HW_LINK_UP, + NTB_EVENT_HW_LINK_DOWN, +}; + +struct ntb_mw { + dma_addr_t phys_addr; + void __iomem *vbase; + resource_size_t bar_sz; +}; + +struct ntb_db_cb { + int (*callback)(void *data, int db_num); + unsigned int db_num; + void *data; + struct ntb_device *ndev; + struct tasklet_struct irq_work; +}; + +#define WA_SNB_ERR 0x00000001 + +struct ntb_device { + struct pci_dev *pdev; + struct msix_entry *msix_entries; + void __iomem *reg_base; + struct ntb_mw *mw; + struct { + unsigned char max_mw; + unsigned char max_spads; + unsigned char max_db_bits; + unsigned char msix_cnt; + } limits; + struct { + void __iomem *ldb; + void __iomem *ldb_mask; + void __iomem *rdb; + void __iomem *bar2_xlat; + void __iomem *bar4_xlat; + void __iomem *bar5_xlat; + void __iomem *spad_write; + void __iomem *spad_read; + void __iomem *lnk_cntl; + void __iomem *lnk_stat; + void __iomem *spci_cmd; + } reg_ofs; + struct ntb_transport *ntb_transport; + void (*event_cb)(void *handle, enum ntb_hw_event event); + + struct ntb_db_cb *db_cb; + unsigned char hw_type; + unsigned char conn_type; + unsigned char dev_type; + unsigned char num_msix; + unsigned char bits_per_vector; + unsigned char max_cbs; + unsigned char link_width; + unsigned char link_speed; + unsigned char link_status; + unsigned char split_bar; + + struct delayed_work hb_timer; + unsigned long last_ts; + + struct delayed_work lr_timer; + + struct dentry *debugfs_dir; + struct dentry *debugfs_info; + + unsigned int wa_flags; +}; + +/** + * ntb_max_cbs() - return the max callbacks + * @ndev: pointer to ntb_device instance + * + * Given the ntb pointer, return the maximum number of callbacks + * + * RETURNS: the maximum number of callbacks + */ +static inline unsigned char ntb_max_cbs(struct ntb_device *ndev) +{ + return ndev->max_cbs; +} + +/** + * ntb_max_mw() - return the max number of memory windows + * @ndev: pointer to ntb_device instance + * + * Given the ntb pointer, return the maximum number of memory windows + * + * RETURNS: the maximum number of memory windows + */ +static inline unsigned char ntb_max_mw(struct ntb_device *ndev) +{ + return ndev->limits.max_mw; +} + +/** + * ntb_hw_link_status() - return the hardware link status + * @ndev: pointer to ntb_device instance + * + * Returns true if the hardware is connected to the remote system + * + * RETURNS: true or false based on the hardware link state + */ +static inline bool ntb_hw_link_status(struct ntb_device *ndev) +{ + return ndev->link_status == NTB_LINK_UP; +} + +/** + * ntb_query_pdev() - return the pci_dev pointer + * @ndev: pointer to ntb_device instance + * + * Given the ntb pointer, return the pci_dev pointer for the NTB hardware device + * + * RETURNS: a pointer to the ntb pci_dev + */ +static inline struct pci_dev *ntb_query_pdev(struct ntb_device *ndev) +{ + return ndev->pdev; +} + +/** + * ntb_query_debugfs() - return the debugfs pointer + * @ndev: pointer to ntb_device instance + * + * Given the ntb pointer, return the debugfs directory pointer for the NTB + * hardware device + * + * RETURNS: a pointer to the debugfs directory + */ +static inline struct dentry *ntb_query_debugfs(struct ntb_device *ndev) +{ + return ndev->debugfs_dir; +} + +struct ntb_device *ntb_register_transport(struct pci_dev *pdev, + void *transport); +void ntb_unregister_transport(struct ntb_device *ndev); +void ntb_set_mw_addr(struct ntb_device *ndev, unsigned int mw, u64 addr); +int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx, + void *data, int (*db_cb_func)(void *data, + int db_num)); +void ntb_unregister_db_callback(struct ntb_device *ndev, unsigned int idx); +int ntb_register_event_callback(struct ntb_device *ndev, + void (*event_cb_func)(void *handle, + enum ntb_hw_event event)); +void ntb_unregister_event_callback(struct ntb_device *ndev); +int ntb_get_max_spads(struct ntb_device *ndev); +int ntb_write_local_spad(struct ntb_device *ndev, unsigned int idx, u32 val); +int ntb_read_local_spad(struct ntb_device *ndev, unsigned int idx, u32 *val); +int ntb_write_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 val); +int ntb_read_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 *val); +resource_size_t ntb_get_mw_base(struct ntb_device *ndev, unsigned int mw); +void __iomem *ntb_get_mw_vbase(struct ntb_device *ndev, unsigned int mw); +u64 ntb_get_mw_size(struct ntb_device *ndev, unsigned int mw); +void ntb_ring_doorbell(struct ntb_device *ndev, unsigned int idx); +void *ntb_find_transport(struct pci_dev *pdev); + +int ntb_transport_init(struct pci_dev *pdev); +void ntb_transport_free(void *transport); diff --git a/drivers/ntb/ntb_hw.c b/drivers/ntb/ntb_hw.c deleted file mode 100644 index 3f6738612f45..000000000000 --- a/drivers/ntb/ntb_hw.c +++ /dev/null @@ -1,1895 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2012 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * BSD LICENSE - * - * Copyright(c) 2012 Intel Corporation. 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 copy - * 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. - * - * Intel PCIe NTB Linux driver - * - * Contact Information: - * Jon Mason - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include "ntb_hw.h" -#include "ntb_regs.h" - -#define NTB_NAME "Intel(R) PCI-E Non-Transparent Bridge Driver" -#define NTB_VER "1.0" - -MODULE_DESCRIPTION(NTB_NAME); -MODULE_VERSION(NTB_VER); -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_AUTHOR("Intel Corporation"); - -enum { - NTB_CONN_TRANSPARENT = 0, - NTB_CONN_B2B, - NTB_CONN_RP, -}; - -enum { - NTB_DEV_USD = 0, - NTB_DEV_DSD, -}; - -enum { - SNB_HW = 0, - BWD_HW, -}; - -static struct dentry *debugfs_dir; - -#define BWD_LINK_RECOVERY_TIME 500 - -/* Translate memory window 0,1,2 to BAR 2,4,5 */ -#define MW_TO_BAR(mw) (mw == 0 ? 2 : (mw == 1 ? 4 : 5)) - -static const struct pci_device_id ntb_pci_tbl[] = { - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_BWD)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_JSF)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_SNB)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_IVT)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_HSX)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_JSF)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_SNB)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_IVT)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_HSX)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_JSF)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_SNB)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_IVT)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_HSX)}, - {0} -}; -MODULE_DEVICE_TABLE(pci, ntb_pci_tbl); - -static int is_ntb_xeon(struct ntb_device *ndev) -{ - switch (ndev->pdev->device) { - case PCI_DEVICE_ID_INTEL_NTB_SS_JSF: - case PCI_DEVICE_ID_INTEL_NTB_SS_SNB: - case PCI_DEVICE_ID_INTEL_NTB_SS_IVT: - case PCI_DEVICE_ID_INTEL_NTB_SS_HSX: - case PCI_DEVICE_ID_INTEL_NTB_PS_JSF: - case PCI_DEVICE_ID_INTEL_NTB_PS_SNB: - case PCI_DEVICE_ID_INTEL_NTB_PS_IVT: - case PCI_DEVICE_ID_INTEL_NTB_PS_HSX: - case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF: - case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB: - case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT: - case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX: - return 1; - default: - return 0; - } - - return 0; -} - -static int is_ntb_atom(struct ntb_device *ndev) -{ - switch (ndev->pdev->device) { - case PCI_DEVICE_ID_INTEL_NTB_B2B_BWD: - return 1; - default: - return 0; - } - - return 0; -} - -static void ntb_set_errata_flags(struct ntb_device *ndev) -{ - switch (ndev->pdev->device) { - /* - * this workaround applies to all platform up to IvyBridge - * Haswell has splitbar support and use a different workaround - */ - case PCI_DEVICE_ID_INTEL_NTB_SS_JSF: - case PCI_DEVICE_ID_INTEL_NTB_SS_SNB: - case PCI_DEVICE_ID_INTEL_NTB_SS_IVT: - case PCI_DEVICE_ID_INTEL_NTB_SS_HSX: - case PCI_DEVICE_ID_INTEL_NTB_PS_JSF: - case PCI_DEVICE_ID_INTEL_NTB_PS_SNB: - case PCI_DEVICE_ID_INTEL_NTB_PS_IVT: - case PCI_DEVICE_ID_INTEL_NTB_PS_HSX: - case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF: - case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB: - case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT: - case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX: - ndev->wa_flags |= WA_SNB_ERR; - break; - } -} - -/** - * ntb_register_event_callback() - register event callback - * @ndev: pointer to ntb_device instance - * @func: callback function to register - * - * This function registers a callback for any HW driver events such as link - * up/down, power management notices and etc. - * - * RETURNS: An appropriate -ERRNO error value on error, or zero for success. - */ -int ntb_register_event_callback(struct ntb_device *ndev, - void (*func)(void *handle, - enum ntb_hw_event event)) -{ - if (ndev->event_cb) - return -EINVAL; - - ndev->event_cb = func; - - return 0; -} - -/** - * ntb_unregister_event_callback() - unregisters the event callback - * @ndev: pointer to ntb_device instance - * - * This function unregisters the existing callback from transport - */ -void ntb_unregister_event_callback(struct ntb_device *ndev) -{ - ndev->event_cb = NULL; -} - -static void ntb_irq_work(unsigned long data) -{ - struct ntb_db_cb *db_cb = (struct ntb_db_cb *)data; - int rc; - - rc = db_cb->callback(db_cb->data, db_cb->db_num); - if (rc) - tasklet_schedule(&db_cb->irq_work); - else { - struct ntb_device *ndev = db_cb->ndev; - unsigned long mask; - - mask = readw(ndev->reg_ofs.ldb_mask); - clear_bit(db_cb->db_num * ndev->bits_per_vector, &mask); - writew(mask, ndev->reg_ofs.ldb_mask); - } -} - -/** - * ntb_register_db_callback() - register a callback for doorbell interrupt - * @ndev: pointer to ntb_device instance - * @idx: doorbell index to register callback, zero based - * @data: pointer to be returned to caller with every callback - * @func: callback function to register - * - * This function registers a callback function for the doorbell interrupt - * on the primary side. The function will unmask the doorbell as well to - * allow interrupt. - * - * RETURNS: An appropriate -ERRNO error value on error, or zero for success. - */ -int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx, - void *data, int (*func)(void *data, int db_num)) -{ - unsigned long mask; - - if (idx >= ndev->max_cbs || ndev->db_cb[idx].callback) { - dev_warn(&ndev->pdev->dev, "Invalid Index.\n"); - return -EINVAL; - } - - ndev->db_cb[idx].callback = func; - ndev->db_cb[idx].data = data; - ndev->db_cb[idx].ndev = ndev; - - tasklet_init(&ndev->db_cb[idx].irq_work, ntb_irq_work, - (unsigned long) &ndev->db_cb[idx]); - - /* unmask interrupt */ - mask = readw(ndev->reg_ofs.ldb_mask); - clear_bit(idx * ndev->bits_per_vector, &mask); - writew(mask, ndev->reg_ofs.ldb_mask); - - return 0; -} - -/** - * ntb_unregister_db_callback() - unregister a callback for doorbell interrupt - * @ndev: pointer to ntb_device instance - * @idx: doorbell index to register callback, zero based - * - * This function unregisters a callback function for the doorbell interrupt - * on the primary side. The function will also mask the said doorbell. - */ -void ntb_unregister_db_callback(struct ntb_device *ndev, unsigned int idx) -{ - unsigned long mask; - - if (idx >= ndev->max_cbs || !ndev->db_cb[idx].callback) - return; - - mask = readw(ndev->reg_ofs.ldb_mask); - set_bit(idx * ndev->bits_per_vector, &mask); - writew(mask, ndev->reg_ofs.ldb_mask); - - tasklet_disable(&ndev->db_cb[idx].irq_work); - - ndev->db_cb[idx].callback = NULL; -} - -/** - * ntb_find_transport() - find the transport pointer - * @transport: pointer to pci device - * - * Given the pci device pointer, return the transport pointer passed in when - * the transport attached when it was inited. - * - * RETURNS: pointer to transport. - */ -void *ntb_find_transport(struct pci_dev *pdev) -{ - struct ntb_device *ndev = pci_get_drvdata(pdev); - return ndev->ntb_transport; -} - -/** - * ntb_register_transport() - Register NTB transport with NTB HW driver - * @transport: transport identifier - * - * This function allows a transport to reserve the hardware driver for - * NTB usage. - * - * RETURNS: pointer to ntb_device, NULL on error. - */ -struct ntb_device *ntb_register_transport(struct pci_dev *pdev, void *transport) -{ - struct ntb_device *ndev = pci_get_drvdata(pdev); - - if (ndev->ntb_transport) - return NULL; - - ndev->ntb_transport = transport; - return ndev; -} - -/** - * ntb_unregister_transport() - Unregister the transport with the NTB HW driver - * @ndev - ntb_device of the transport to be freed - * - * This function unregisters the transport from the HW driver and performs any - * necessary cleanups. - */ -void ntb_unregister_transport(struct ntb_device *ndev) -{ - int i; - - if (!ndev->ntb_transport) - return; - - for (i = 0; i < ndev->max_cbs; i++) - ntb_unregister_db_callback(ndev, i); - - ntb_unregister_event_callback(ndev); - ndev->ntb_transport = NULL; -} - -/** - * ntb_write_local_spad() - write to the secondary scratchpad register - * @ndev: pointer to ntb_device instance - * @idx: index to the scratchpad register, 0 based - * @val: the data value to put into the register - * - * This function allows writing of a 32bit value to the indexed scratchpad - * register. This writes over the data mirrored to the local scratchpad register - * by the remote system. - * - * RETURNS: An appropriate -ERRNO error value on error, or zero for success. - */ -int ntb_write_local_spad(struct ntb_device *ndev, unsigned int idx, u32 val) -{ - if (idx >= ndev->limits.max_spads) - return -EINVAL; - - dev_dbg(&ndev->pdev->dev, "Writing %x to local scratch pad index %d\n", - val, idx); - writel(val, ndev->reg_ofs.spad_read + idx * 4); - - return 0; -} - -/** - * ntb_read_local_spad() - read from the primary scratchpad register - * @ndev: pointer to ntb_device instance - * @idx: index to scratchpad register, 0 based - * @val: pointer to 32bit integer for storing the register value - * - * This function allows reading of the 32bit scratchpad register on - * the primary (internal) side. This allows the local system to read data - * written and mirrored to the scratchpad register by the remote system. - * - * RETURNS: An appropriate -ERRNO error value on error, or zero for success. - */ -int ntb_read_local_spad(struct ntb_device *ndev, unsigned int idx, u32 *val) -{ - if (idx >= ndev->limits.max_spads) - return -EINVAL; - - *val = readl(ndev->reg_ofs.spad_write + idx * 4); - dev_dbg(&ndev->pdev->dev, - "Reading %x from local scratch pad index %d\n", *val, idx); - - return 0; -} - -/** - * ntb_write_remote_spad() - write to the secondary scratchpad register - * @ndev: pointer to ntb_device instance - * @idx: index to the scratchpad register, 0 based - * @val: the data value to put into the register - * - * This function allows writing of a 32bit value to the indexed scratchpad - * register. The register resides on the secondary (external) side. This allows - * the local system to write data to be mirrored to the remote systems - * scratchpad register. - * - * RETURNS: An appropriate -ERRNO error value on error, or zero for success. - */ -int ntb_write_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 val) -{ - if (idx >= ndev->limits.max_spads) - return -EINVAL; - - dev_dbg(&ndev->pdev->dev, "Writing %x to remote scratch pad index %d\n", - val, idx); - writel(val, ndev->reg_ofs.spad_write + idx * 4); - - return 0; -} - -/** - * ntb_read_remote_spad() - read from the primary scratchpad register - * @ndev: pointer to ntb_device instance - * @idx: index to scratchpad register, 0 based - * @val: pointer to 32bit integer for storing the register value - * - * This function allows reading of the 32bit scratchpad register on - * the primary (internal) side. This alloows the local system to read the data - * it wrote to be mirrored on the remote system. - * - * RETURNS: An appropriate -ERRNO error value on error, or zero for success. - */ -int ntb_read_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 *val) -{ - if (idx >= ndev->limits.max_spads) - return -EINVAL; - - *val = readl(ndev->reg_ofs.spad_read + idx * 4); - dev_dbg(&ndev->pdev->dev, - "Reading %x from remote scratch pad index %d\n", *val, idx); - - return 0; -} - -/** - * ntb_get_mw_base() - get addr for the NTB memory window - * @ndev: pointer to ntb_device instance - * @mw: memory window number - * - * This function provides the base address of the memory window specified. - * - * RETURNS: address, or NULL on error. - */ -resource_size_t ntb_get_mw_base(struct ntb_device *ndev, unsigned int mw) -{ - if (mw >= ntb_max_mw(ndev)) - return 0; - - return pci_resource_start(ndev->pdev, MW_TO_BAR(mw)); -} - -/** - * ntb_get_mw_vbase() - get virtual addr for the NTB memory window - * @ndev: pointer to ntb_device instance - * @mw: memory window number - * - * This function provides the base virtual address of the memory window - * specified. - * - * RETURNS: pointer to virtual address, or NULL on error. - */ -void __iomem *ntb_get_mw_vbase(struct ntb_device *ndev, unsigned int mw) -{ - if (mw >= ntb_max_mw(ndev)) - return NULL; - - return ndev->mw[mw].vbase; -} - -/** - * ntb_get_mw_size() - return size of NTB memory window - * @ndev: pointer to ntb_device instance - * @mw: memory window number - * - * This function provides the physical size of the memory window specified - * - * RETURNS: the size of the memory window or zero on error - */ -u64 ntb_get_mw_size(struct ntb_device *ndev, unsigned int mw) -{ - if (mw >= ntb_max_mw(ndev)) - return 0; - - return ndev->mw[mw].bar_sz; -} - -/** - * ntb_set_mw_addr - set the memory window address - * @ndev: pointer to ntb_device instance - * @mw: memory window number - * @addr: base address for data - * - * This function sets the base physical address of the memory window. This - * memory address is where data from the remote system will be transfered into - * or out of depending on how the transport is configured. - */ -void ntb_set_mw_addr(struct ntb_device *ndev, unsigned int mw, u64 addr) -{ - if (mw >= ntb_max_mw(ndev)) - return; - - dev_dbg(&ndev->pdev->dev, "Writing addr %Lx to BAR %d\n", addr, - MW_TO_BAR(mw)); - - ndev->mw[mw].phys_addr = addr; - - switch (MW_TO_BAR(mw)) { - case NTB_BAR_23: - writeq(addr, ndev->reg_ofs.bar2_xlat); - break; - case NTB_BAR_4: - if (ndev->split_bar) - writel(addr, ndev->reg_ofs.bar4_xlat); - else - writeq(addr, ndev->reg_ofs.bar4_xlat); - break; - case NTB_BAR_5: - writel(addr, ndev->reg_ofs.bar5_xlat); - break; - } -} - -/** - * ntb_ring_doorbell() - Set the doorbell on the secondary/external side - * @ndev: pointer to ntb_device instance - * @db: doorbell to ring - * - * This function allows triggering of a doorbell on the secondary/external - * side that will initiate an interrupt on the remote host - * - * RETURNS: An appropriate -ERRNO error value on error, or zero for success. - */ -void ntb_ring_doorbell(struct ntb_device *ndev, unsigned int db) -{ - dev_dbg(&ndev->pdev->dev, "%s: ringing doorbell %d\n", __func__, db); - - if (ndev->hw_type == BWD_HW) - writeq((u64) 1 << db, ndev->reg_ofs.rdb); - else - writew(((1 << ndev->bits_per_vector) - 1) << - (db * ndev->bits_per_vector), ndev->reg_ofs.rdb); -} - -static void bwd_recover_link(struct ntb_device *ndev) -{ - u32 status; - - /* Driver resets the NTB ModPhy lanes - magic! */ - writeb(0xe0, ndev->reg_base + BWD_MODPHY_PCSREG6); - writeb(0x40, ndev->reg_base + BWD_MODPHY_PCSREG4); - writeb(0x60, ndev->reg_base + BWD_MODPHY_PCSREG4); - writeb(0x60, ndev->reg_base + BWD_MODPHY_PCSREG6); - - /* Driver waits 100ms to allow the NTB ModPhy to settle */ - msleep(100); - - /* Clear AER Errors, write to clear */ - status = readl(ndev->reg_base + BWD_ERRCORSTS_OFFSET); - dev_dbg(&ndev->pdev->dev, "ERRCORSTS = %x\n", status); - status &= PCI_ERR_COR_REP_ROLL; - writel(status, ndev->reg_base + BWD_ERRCORSTS_OFFSET); - - /* Clear unexpected electrical idle event in LTSSM, write to clear */ - status = readl(ndev->reg_base + BWD_LTSSMERRSTS0_OFFSET); - dev_dbg(&ndev->pdev->dev, "LTSSMERRSTS0 = %x\n", status); - status |= BWD_LTSSMERRSTS0_UNEXPECTEDEI; - writel(status, ndev->reg_base + BWD_LTSSMERRSTS0_OFFSET); - - /* Clear DeSkew Buffer error, write to clear */ - status = readl(ndev->reg_base + BWD_DESKEWSTS_OFFSET); - dev_dbg(&ndev->pdev->dev, "DESKEWSTS = %x\n", status); - status |= BWD_DESKEWSTS_DBERR; - writel(status, ndev->reg_base + BWD_DESKEWSTS_OFFSET); - - status = readl(ndev->reg_base + BWD_IBSTERRRCRVSTS0_OFFSET); - dev_dbg(&ndev->pdev->dev, "IBSTERRRCRVSTS0 = %x\n", status); - status &= BWD_IBIST_ERR_OFLOW; - writel(status, ndev->reg_base + BWD_IBSTERRRCRVSTS0_OFFSET); - - /* Releases the NTB state machine to allow the link to retrain */ - status = readl(ndev->reg_base + BWD_LTSSMSTATEJMP_OFFSET); - dev_dbg(&ndev->pdev->dev, "LTSSMSTATEJMP = %x\n", status); - status &= ~BWD_LTSSMSTATEJMP_FORCEDETECT; - writel(status, ndev->reg_base + BWD_LTSSMSTATEJMP_OFFSET); -} - -static void ntb_link_event(struct ntb_device *ndev, int link_state) -{ - unsigned int event; - - if (ndev->link_status == link_state) - return; - - if (link_state == NTB_LINK_UP) { - u16 status; - - dev_info(&ndev->pdev->dev, "Link Up\n"); - ndev->link_status = NTB_LINK_UP; - event = NTB_EVENT_HW_LINK_UP; - - if (is_ntb_atom(ndev) || - ndev->conn_type == NTB_CONN_TRANSPARENT) - status = readw(ndev->reg_ofs.lnk_stat); - else { - int rc = pci_read_config_word(ndev->pdev, - SNB_LINK_STATUS_OFFSET, - &status); - if (rc) - return; - } - - ndev->link_width = (status & NTB_LINK_WIDTH_MASK) >> 4; - ndev->link_speed = (status & NTB_LINK_SPEED_MASK); - dev_info(&ndev->pdev->dev, "Link Width %d, Link Speed %d\n", - ndev->link_width, ndev->link_speed); - } else { - dev_info(&ndev->pdev->dev, "Link Down\n"); - ndev->link_status = NTB_LINK_DOWN; - event = NTB_EVENT_HW_LINK_DOWN; - /* Don't modify link width/speed, we need it in link recovery */ - } - - /* notify the upper layer if we have an event change */ - if (ndev->event_cb) - ndev->event_cb(ndev->ntb_transport, event); -} - -static int ntb_link_status(struct ntb_device *ndev) -{ - int link_state; - - if (is_ntb_atom(ndev)) { - u32 ntb_cntl; - - ntb_cntl = readl(ndev->reg_ofs.lnk_cntl); - if (ntb_cntl & BWD_CNTL_LINK_DOWN) - link_state = NTB_LINK_DOWN; - else - link_state = NTB_LINK_UP; - } else { - u16 status; - int rc; - - rc = pci_read_config_word(ndev->pdev, SNB_LINK_STATUS_OFFSET, - &status); - if (rc) - return rc; - - if (status & NTB_LINK_STATUS_ACTIVE) - link_state = NTB_LINK_UP; - else - link_state = NTB_LINK_DOWN; - } - - ntb_link_event(ndev, link_state); - - return 0; -} - -static void bwd_link_recovery(struct work_struct *work) -{ - struct ntb_device *ndev = container_of(work, struct ntb_device, - lr_timer.work); - u32 status32; - - bwd_recover_link(ndev); - /* There is a potential race between the 2 NTB devices recovering at the - * same time. If the times are the same, the link will not recover and - * the driver will be stuck in this loop forever. Add a random interval - * to the recovery time to prevent this race. - */ - msleep(BWD_LINK_RECOVERY_TIME + prandom_u32() % BWD_LINK_RECOVERY_TIME); - - status32 = readl(ndev->reg_base + BWD_LTSSMSTATEJMP_OFFSET); - if (status32 & BWD_LTSSMSTATEJMP_FORCEDETECT) - goto retry; - - status32 = readl(ndev->reg_base + BWD_IBSTERRRCRVSTS0_OFFSET); - if (status32 & BWD_IBIST_ERR_OFLOW) - goto retry; - - status32 = readl(ndev->reg_ofs.lnk_cntl); - if (!(status32 & BWD_CNTL_LINK_DOWN)) { - unsigned char speed, width; - u16 status16; - - status16 = readw(ndev->reg_ofs.lnk_stat); - width = (status16 & NTB_LINK_WIDTH_MASK) >> 4; - speed = (status16 & NTB_LINK_SPEED_MASK); - if (ndev->link_width != width || ndev->link_speed != speed) - goto retry; - } - - schedule_delayed_work(&ndev->hb_timer, NTB_HB_TIMEOUT); - return; - -retry: - schedule_delayed_work(&ndev->lr_timer, NTB_HB_TIMEOUT); -} - -/* BWD doesn't have link status interrupt, poll on that platform */ -static void bwd_link_poll(struct work_struct *work) -{ - struct ntb_device *ndev = container_of(work, struct ntb_device, - hb_timer.work); - unsigned long ts = jiffies; - - /* If we haven't gotten an interrupt in a while, check the BWD link - * status bit - */ - if (ts > ndev->last_ts + NTB_HB_TIMEOUT) { - int rc = ntb_link_status(ndev); - if (rc) - dev_err(&ndev->pdev->dev, - "Error determining link status\n"); - - /* Check to see if a link error is the cause of the link down */ - if (ndev->link_status == NTB_LINK_DOWN) { - u32 status32 = readl(ndev->reg_base + - BWD_LTSSMSTATEJMP_OFFSET); - if (status32 & BWD_LTSSMSTATEJMP_FORCEDETECT) { - schedule_delayed_work(&ndev->lr_timer, 0); - return; - } - } - } - - schedule_delayed_work(&ndev->hb_timer, NTB_HB_TIMEOUT); -} - -static int ntb_xeon_setup(struct ntb_device *ndev) -{ - switch (ndev->conn_type) { - case NTB_CONN_B2B: - ndev->reg_ofs.ldb = ndev->reg_base + SNB_PDOORBELL_OFFSET; - ndev->reg_ofs.ldb_mask = ndev->reg_base + SNB_PDBMSK_OFFSET; - ndev->reg_ofs.spad_read = ndev->reg_base + SNB_SPAD_OFFSET; - ndev->reg_ofs.bar2_xlat = ndev->reg_base + SNB_SBAR2XLAT_OFFSET; - ndev->reg_ofs.bar4_xlat = ndev->reg_base + SNB_SBAR4XLAT_OFFSET; - if (ndev->split_bar) - ndev->reg_ofs.bar5_xlat = - ndev->reg_base + SNB_SBAR5XLAT_OFFSET; - ndev->limits.max_spads = SNB_MAX_B2B_SPADS; - - /* There is a Xeon hardware errata related to writes to - * SDOORBELL or B2BDOORBELL in conjunction with inbound access - * to NTB MMIO Space, which may hang the system. To workaround - * this use the second memory window to access the interrupt and - * scratch pad registers on the remote system. - */ - if (ndev->wa_flags & WA_SNB_ERR) { - if (!ndev->mw[ndev->limits.max_mw - 1].bar_sz) - return -EINVAL; - - ndev->limits.max_db_bits = SNB_MAX_DB_BITS; - ndev->reg_ofs.spad_write = - ndev->mw[ndev->limits.max_mw - 1].vbase + - SNB_SPAD_OFFSET; - ndev->reg_ofs.rdb = - ndev->mw[ndev->limits.max_mw - 1].vbase + - SNB_PDOORBELL_OFFSET; - - /* Set the Limit register to 4k, the minimum size, to - * prevent an illegal access - */ - writeq(ndev->mw[1].bar_sz + 0x1000, ndev->reg_base + - SNB_PBAR4LMT_OFFSET); - /* HW errata on the Limit registers. They can only be - * written when the base register is 4GB aligned and - * < 32bit. This should already be the case based on - * the driver defaults, but write the Limit registers - * first just in case. - */ - - ndev->limits.max_mw = SNB_ERRATA_MAX_MW; - } else { - /* HW Errata on bit 14 of b2bdoorbell register. Writes - * will not be mirrored to the remote system. Shrink - * the number of bits by one, since bit 14 is the last - * bit. - */ - ndev->limits.max_db_bits = SNB_MAX_DB_BITS - 1; - ndev->reg_ofs.spad_write = ndev->reg_base + - SNB_B2B_SPAD_OFFSET; - ndev->reg_ofs.rdb = ndev->reg_base + - SNB_B2B_DOORBELL_OFFSET; - - /* Disable the Limit register, just incase it is set to - * something silly. A 64bit write should handle it - * regardless of whether it has a split BAR or not. - */ - writeq(0, ndev->reg_base + SNB_PBAR4LMT_OFFSET); - /* HW errata on the Limit registers. They can only be - * written when the base register is 4GB aligned and - * < 32bit. This should already be the case based on - * the driver defaults, but write the Limit registers - * first just in case. - */ - if (ndev->split_bar) - ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW; - else - ndev->limits.max_mw = SNB_MAX_MW; - } - - /* The Xeon errata workaround requires setting SBAR Base - * addresses to known values, so that the PBAR XLAT can be - * pointed at SBAR0 of the remote system. - */ - if (ndev->dev_type == NTB_DEV_USD) { - writeq(SNB_MBAR23_DSD_ADDR, ndev->reg_base + - SNB_PBAR2XLAT_OFFSET); - if (ndev->wa_flags & WA_SNB_ERR) - writeq(SNB_MBAR01_DSD_ADDR, ndev->reg_base + - SNB_PBAR4XLAT_OFFSET); - else { - if (ndev->split_bar) { - writel(SNB_MBAR4_DSD_ADDR, - ndev->reg_base + - SNB_PBAR4XLAT_OFFSET); - writel(SNB_MBAR5_DSD_ADDR, - ndev->reg_base + - SNB_PBAR5XLAT_OFFSET); - } else - writeq(SNB_MBAR4_DSD_ADDR, - ndev->reg_base + - SNB_PBAR4XLAT_OFFSET); - - /* B2B_XLAT_OFFSET is a 64bit register, but can - * only take 32bit writes - */ - writel(SNB_MBAR01_DSD_ADDR & 0xffffffff, - ndev->reg_base + SNB_B2B_XLAT_OFFSETL); - writel(SNB_MBAR01_DSD_ADDR >> 32, - ndev->reg_base + SNB_B2B_XLAT_OFFSETU); - } - - writeq(SNB_MBAR01_USD_ADDR, ndev->reg_base + - SNB_SBAR0BASE_OFFSET); - writeq(SNB_MBAR23_USD_ADDR, ndev->reg_base + - SNB_SBAR2BASE_OFFSET); - if (ndev->split_bar) { - writel(SNB_MBAR4_USD_ADDR, ndev->reg_base + - SNB_SBAR4BASE_OFFSET); - writel(SNB_MBAR5_USD_ADDR, ndev->reg_base + - SNB_SBAR5BASE_OFFSET); - } else - writeq(SNB_MBAR4_USD_ADDR, ndev->reg_base + - SNB_SBAR4BASE_OFFSET); - } else { - writeq(SNB_MBAR23_USD_ADDR, ndev->reg_base + - SNB_PBAR2XLAT_OFFSET); - if (ndev->wa_flags & WA_SNB_ERR) - writeq(SNB_MBAR01_USD_ADDR, ndev->reg_base + - SNB_PBAR4XLAT_OFFSET); - else { - if (ndev->split_bar) { - writel(SNB_MBAR4_USD_ADDR, - ndev->reg_base + - SNB_PBAR4XLAT_OFFSET); - writel(SNB_MBAR5_USD_ADDR, - ndev->reg_base + - SNB_PBAR5XLAT_OFFSET); - } else - writeq(SNB_MBAR4_USD_ADDR, - ndev->reg_base + - SNB_PBAR4XLAT_OFFSET); - - /* - * B2B_XLAT_OFFSET is a 64bit register, but can - * only take 32bit writes - */ - writel(SNB_MBAR01_USD_ADDR & 0xffffffff, - ndev->reg_base + SNB_B2B_XLAT_OFFSETL); - writel(SNB_MBAR01_USD_ADDR >> 32, - ndev->reg_base + SNB_B2B_XLAT_OFFSETU); - } - writeq(SNB_MBAR01_DSD_ADDR, ndev->reg_base + - SNB_SBAR0BASE_OFFSET); - writeq(SNB_MBAR23_DSD_ADDR, ndev->reg_base + - SNB_SBAR2BASE_OFFSET); - if (ndev->split_bar) { - writel(SNB_MBAR4_DSD_ADDR, ndev->reg_base + - SNB_SBAR4BASE_OFFSET); - writel(SNB_MBAR5_DSD_ADDR, ndev->reg_base + - SNB_SBAR5BASE_OFFSET); - } else - writeq(SNB_MBAR4_DSD_ADDR, ndev->reg_base + - SNB_SBAR4BASE_OFFSET); - - } - break; - case NTB_CONN_RP: - if (ndev->wa_flags & WA_SNB_ERR) { - dev_err(&ndev->pdev->dev, - "NTB-RP disabled due to hardware errata.\n"); - return -EINVAL; - } - - /* Scratch pads need to have exclusive access from the primary - * or secondary side. Halve the num spads so that each side can - * have an equal amount. - */ - ndev->limits.max_spads = SNB_MAX_COMPAT_SPADS / 2; - ndev->limits.max_db_bits = SNB_MAX_DB_BITS; - /* Note: The SDOORBELL is the cause of the errata. You REALLY - * don't want to touch it. - */ - ndev->reg_ofs.rdb = ndev->reg_base + SNB_SDOORBELL_OFFSET; - ndev->reg_ofs.ldb = ndev->reg_base + SNB_PDOORBELL_OFFSET; - ndev->reg_ofs.ldb_mask = ndev->reg_base + SNB_PDBMSK_OFFSET; - /* Offset the start of the spads to correspond to whether it is - * primary or secondary - */ - ndev->reg_ofs.spad_write = ndev->reg_base + SNB_SPAD_OFFSET + - ndev->limits.max_spads * 4; - ndev->reg_ofs.spad_read = ndev->reg_base + SNB_SPAD_OFFSET; - ndev->reg_ofs.bar2_xlat = ndev->reg_base + SNB_SBAR2XLAT_OFFSET; - ndev->reg_ofs.bar4_xlat = ndev->reg_base + SNB_SBAR4XLAT_OFFSET; - if (ndev->split_bar) { - ndev->reg_ofs.bar5_xlat = - ndev->reg_base + SNB_SBAR5XLAT_OFFSET; - ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW; - } else - ndev->limits.max_mw = SNB_MAX_MW; - break; - case NTB_CONN_TRANSPARENT: - if (ndev->wa_flags & WA_SNB_ERR) { - dev_err(&ndev->pdev->dev, - "NTB-TRANSPARENT disabled due to hardware errata.\n"); - return -EINVAL; - } - - /* Scratch pads need to have exclusive access from the primary - * or secondary side. Halve the num spads so that each side can - * have an equal amount. - */ - ndev->limits.max_spads = SNB_MAX_COMPAT_SPADS / 2; - ndev->limits.max_db_bits = SNB_MAX_DB_BITS; - ndev->reg_ofs.rdb = ndev->reg_base + SNB_PDOORBELL_OFFSET; - ndev->reg_ofs.ldb = ndev->reg_base + SNB_SDOORBELL_OFFSET; - ndev->reg_ofs.ldb_mask = ndev->reg_base + SNB_SDBMSK_OFFSET; - ndev->reg_ofs.spad_write = ndev->reg_base + SNB_SPAD_OFFSET; - /* Offset the start of the spads to correspond to whether it is - * primary or secondary - */ - ndev->reg_ofs.spad_read = ndev->reg_base + SNB_SPAD_OFFSET + - ndev->limits.max_spads * 4; - ndev->reg_ofs.bar2_xlat = ndev->reg_base + SNB_PBAR2XLAT_OFFSET; - ndev->reg_ofs.bar4_xlat = ndev->reg_base + SNB_PBAR4XLAT_OFFSET; - - if (ndev->split_bar) { - ndev->reg_ofs.bar5_xlat = - ndev->reg_base + SNB_PBAR5XLAT_OFFSET; - ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW; - } else - ndev->limits.max_mw = SNB_MAX_MW; - break; - default: - /* - * we should never hit this. the detect function should've - * take cared of everything. - */ - return -EINVAL; - } - - ndev->reg_ofs.lnk_cntl = ndev->reg_base + SNB_NTBCNTL_OFFSET; - ndev->reg_ofs.lnk_stat = ndev->reg_base + SNB_SLINK_STATUS_OFFSET; - ndev->reg_ofs.spci_cmd = ndev->reg_base + SNB_PCICMD_OFFSET; - - ndev->limits.msix_cnt = SNB_MSIX_CNT; - ndev->bits_per_vector = SNB_DB_BITS_PER_VEC; - - return 0; -} - -static int ntb_bwd_setup(struct ntb_device *ndev) -{ - int rc; - u32 val; - - ndev->hw_type = BWD_HW; - - rc = pci_read_config_dword(ndev->pdev, NTB_PPD_OFFSET, &val); - if (rc) - return rc; - - switch ((val & BWD_PPD_CONN_TYPE) >> 8) { - case NTB_CONN_B2B: - ndev->conn_type = NTB_CONN_B2B; - break; - case NTB_CONN_RP: - default: - dev_err(&ndev->pdev->dev, "Unsupported NTB configuration\n"); - return -EINVAL; - } - - if (val & BWD_PPD_DEV_TYPE) - ndev->dev_type = NTB_DEV_DSD; - else - ndev->dev_type = NTB_DEV_USD; - - /* Initiate PCI-E link training */ - rc = pci_write_config_dword(ndev->pdev, NTB_PPD_OFFSET, - val | BWD_PPD_INIT_LINK); - if (rc) - return rc; - - ndev->reg_ofs.ldb = ndev->reg_base + BWD_PDOORBELL_OFFSET; - ndev->reg_ofs.ldb_mask = ndev->reg_base + BWD_PDBMSK_OFFSET; - ndev->reg_ofs.rdb = ndev->reg_base + BWD_B2B_DOORBELL_OFFSET; - ndev->reg_ofs.bar2_xlat = ndev->reg_base + BWD_SBAR2XLAT_OFFSET; - ndev->reg_ofs.bar4_xlat = ndev->reg_base + BWD_SBAR4XLAT_OFFSET; - ndev->reg_ofs.lnk_cntl = ndev->reg_base + BWD_NTBCNTL_OFFSET; - ndev->reg_ofs.lnk_stat = ndev->reg_base + BWD_LINK_STATUS_OFFSET; - ndev->reg_ofs.spad_read = ndev->reg_base + BWD_SPAD_OFFSET; - ndev->reg_ofs.spad_write = ndev->reg_base + BWD_B2B_SPAD_OFFSET; - ndev->reg_ofs.spci_cmd = ndev->reg_base + BWD_PCICMD_OFFSET; - ndev->limits.max_mw = BWD_MAX_MW; - ndev->limits.max_spads = BWD_MAX_SPADS; - ndev->limits.max_db_bits = BWD_MAX_DB_BITS; - ndev->limits.msix_cnt = BWD_MSIX_CNT; - ndev->bits_per_vector = BWD_DB_BITS_PER_VEC; - - /* Since bwd doesn't have a link interrupt, setup a poll timer */ - INIT_DELAYED_WORK(&ndev->hb_timer, bwd_link_poll); - INIT_DELAYED_WORK(&ndev->lr_timer, bwd_link_recovery); - schedule_delayed_work(&ndev->hb_timer, NTB_HB_TIMEOUT); - - return 0; -} - -static int ntb_device_setup(struct ntb_device *ndev) -{ - int rc; - - if (is_ntb_xeon(ndev)) - rc = ntb_xeon_setup(ndev); - else if (is_ntb_atom(ndev)) - rc = ntb_bwd_setup(ndev); - else - rc = -ENODEV; - - if (rc) - return rc; - - if (ndev->conn_type == NTB_CONN_B2B) - /* Enable Bus Master and Memory Space on the secondary side */ - writew(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER, - ndev->reg_ofs.spci_cmd); - - return 0; -} - -static void ntb_device_free(struct ntb_device *ndev) -{ - if (is_ntb_atom(ndev)) { - cancel_delayed_work_sync(&ndev->hb_timer); - cancel_delayed_work_sync(&ndev->lr_timer); - } -} - -static irqreturn_t bwd_callback_msix_irq(int irq, void *data) -{ - struct ntb_db_cb *db_cb = data; - struct ntb_device *ndev = db_cb->ndev; - unsigned long mask; - - dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for DB %d\n", irq, - db_cb->db_num); - - mask = readw(ndev->reg_ofs.ldb_mask); - set_bit(db_cb->db_num * ndev->bits_per_vector, &mask); - writew(mask, ndev->reg_ofs.ldb_mask); - - tasklet_schedule(&db_cb->irq_work); - - /* No need to check for the specific HB irq, any interrupt means - * we're connected. - */ - ndev->last_ts = jiffies; - - writeq((u64) 1 << db_cb->db_num, ndev->reg_ofs.ldb); - - return IRQ_HANDLED; -} - -static irqreturn_t xeon_callback_msix_irq(int irq, void *data) -{ - struct ntb_db_cb *db_cb = data; - struct ntb_device *ndev = db_cb->ndev; - unsigned long mask; - - dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for DB %d\n", irq, - db_cb->db_num); - - mask = readw(ndev->reg_ofs.ldb_mask); - set_bit(db_cb->db_num * ndev->bits_per_vector, &mask); - writew(mask, ndev->reg_ofs.ldb_mask); - - tasklet_schedule(&db_cb->irq_work); - - /* On Sandybridge, there are 16 bits in the interrupt register - * but only 4 vectors. So, 5 bits are assigned to the first 3 - * vectors, with the 4th having a single bit for link - * interrupts. - */ - writew(((1 << ndev->bits_per_vector) - 1) << - (db_cb->db_num * ndev->bits_per_vector), ndev->reg_ofs.ldb); - - return IRQ_HANDLED; -} - -/* Since we do not have a HW doorbell in BWD, this is only used in JF/JT */ -static irqreturn_t xeon_event_msix_irq(int irq, void *dev) -{ - struct ntb_device *ndev = dev; - int rc; - - dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for Events\n", irq); - - rc = ntb_link_status(ndev); - if (rc) - dev_err(&ndev->pdev->dev, "Error determining link status\n"); - - /* bit 15 is always the link bit */ - writew(1 << SNB_LINK_DB, ndev->reg_ofs.ldb); - - return IRQ_HANDLED; -} - -static irqreturn_t ntb_interrupt(int irq, void *dev) -{ - struct ntb_device *ndev = dev; - unsigned int i = 0; - - if (is_ntb_atom(ndev)) { - u64 ldb = readq(ndev->reg_ofs.ldb); - - dev_dbg(&ndev->pdev->dev, "irq %d - ldb = %Lx\n", irq, ldb); - - while (ldb) { - i = __ffs(ldb); - ldb &= ldb - 1; - bwd_callback_msix_irq(irq, &ndev->db_cb[i]); - } - } else { - u16 ldb = readw(ndev->reg_ofs.ldb); - - dev_dbg(&ndev->pdev->dev, "irq %d - ldb = %x\n", irq, ldb); - - if (ldb & SNB_DB_HW_LINK) { - xeon_event_msix_irq(irq, dev); - ldb &= ~SNB_DB_HW_LINK; - } - - while (ldb) { - i = __ffs(ldb); - ldb &= ldb - 1; - xeon_callback_msix_irq(irq, &ndev->db_cb[i]); - } - } - - return IRQ_HANDLED; -} - -static int ntb_setup_snb_msix(struct ntb_device *ndev, int msix_entries) -{ - struct pci_dev *pdev = ndev->pdev; - struct msix_entry *msix; - int rc, i; - - if (msix_entries < ndev->limits.msix_cnt) - return -ENOSPC; - - rc = pci_enable_msix_exact(pdev, ndev->msix_entries, msix_entries); - if (rc < 0) - return rc; - - for (i = 0; i < msix_entries; i++) { - msix = &ndev->msix_entries[i]; - WARN_ON(!msix->vector); - - if (i == msix_entries - 1) { - rc = request_irq(msix->vector, - xeon_event_msix_irq, 0, - "ntb-event-msix", ndev); - if (rc) - goto err; - } else { - rc = request_irq(msix->vector, - xeon_callback_msix_irq, 0, - "ntb-callback-msix", - &ndev->db_cb[i]); - if (rc) - goto err; - } - } - - ndev->num_msix = msix_entries; - ndev->max_cbs = msix_entries - 1; - - return 0; - -err: - while (--i >= 0) { - /* Code never reaches here for entry nr 'ndev->num_msix - 1' */ - msix = &ndev->msix_entries[i]; - free_irq(msix->vector, &ndev->db_cb[i]); - } - - pci_disable_msix(pdev); - ndev->num_msix = 0; - - return rc; -} - -static int ntb_setup_bwd_msix(struct ntb_device *ndev, int msix_entries) -{ - struct pci_dev *pdev = ndev->pdev; - struct msix_entry *msix; - int rc, i; - - msix_entries = pci_enable_msix_range(pdev, ndev->msix_entries, - 1, msix_entries); - if (msix_entries < 0) - return msix_entries; - - for (i = 0; i < msix_entries; i++) { - msix = &ndev->msix_entries[i]; - WARN_ON(!msix->vector); - - rc = request_irq(msix->vector, bwd_callback_msix_irq, 0, - "ntb-callback-msix", &ndev->db_cb[i]); - if (rc) - goto err; - } - - ndev->num_msix = msix_entries; - ndev->max_cbs = msix_entries; - - return 0; - -err: - while (--i >= 0) - free_irq(msix->vector, &ndev->db_cb[i]); - - pci_disable_msix(pdev); - ndev->num_msix = 0; - - return rc; -} - -static int ntb_setup_msix(struct ntb_device *ndev) -{ - struct pci_dev *pdev = ndev->pdev; - int msix_entries; - int rc, i; - - msix_entries = pci_msix_vec_count(pdev); - if (msix_entries < 0) { - rc = msix_entries; - goto err; - } else if (msix_entries > ndev->limits.msix_cnt) { - rc = -EINVAL; - goto err; - } - - ndev->msix_entries = kmalloc(sizeof(struct msix_entry) * msix_entries, - GFP_KERNEL); - if (!ndev->msix_entries) { - rc = -ENOMEM; - goto err; - } - - for (i = 0; i < msix_entries; i++) - ndev->msix_entries[i].entry = i; - - if (is_ntb_atom(ndev)) - rc = ntb_setup_bwd_msix(ndev, msix_entries); - else - rc = ntb_setup_snb_msix(ndev, msix_entries); - if (rc) - goto err1; - - return 0; - -err1: - kfree(ndev->msix_entries); -err: - dev_err(&pdev->dev, "Error allocating MSI-X interrupt\n"); - return rc; -} - -static int ntb_setup_msi(struct ntb_device *ndev) -{ - struct pci_dev *pdev = ndev->pdev; - int rc; - - rc = pci_enable_msi(pdev); - if (rc) - return rc; - - rc = request_irq(pdev->irq, ntb_interrupt, 0, "ntb-msi", ndev); - if (rc) { - pci_disable_msi(pdev); - dev_err(&pdev->dev, "Error allocating MSI interrupt\n"); - return rc; - } - - return 0; -} - -static int ntb_setup_intx(struct ntb_device *ndev) -{ - struct pci_dev *pdev = ndev->pdev; - int rc; - - /* Verify intx is enabled */ - pci_intx(pdev, 1); - - rc = request_irq(pdev->irq, ntb_interrupt, IRQF_SHARED, "ntb-intx", - ndev); - if (rc) - return rc; - - return 0; -} - -static int ntb_setup_interrupts(struct ntb_device *ndev) -{ - int rc; - - /* On BWD, disable all interrupts. On SNB, disable all but Link - * Interrupt. The rest will be unmasked as callbacks are registered. - */ - if (is_ntb_atom(ndev)) - writeq(~0, ndev->reg_ofs.ldb_mask); - else { - u16 var = 1 << SNB_LINK_DB; - writew(~var, ndev->reg_ofs.ldb_mask); - } - - rc = ntb_setup_msix(ndev); - if (!rc) - goto done; - - ndev->bits_per_vector = 1; - ndev->max_cbs = ndev->limits.max_db_bits; - - rc = ntb_setup_msi(ndev); - if (!rc) - goto done; - - rc = ntb_setup_intx(ndev); - if (rc) { - dev_err(&ndev->pdev->dev, "no usable interrupts\n"); - return rc; - } - -done: - return 0; -} - -static void ntb_free_interrupts(struct ntb_device *ndev) -{ - struct pci_dev *pdev = ndev->pdev; - - /* mask interrupts */ - if (is_ntb_atom(ndev)) - writeq(~0, ndev->reg_ofs.ldb_mask); - else - writew(~0, ndev->reg_ofs.ldb_mask); - - if (ndev->num_msix) { - struct msix_entry *msix; - u32 i; - - for (i = 0; i < ndev->num_msix; i++) { - msix = &ndev->msix_entries[i]; - if (is_ntb_xeon(ndev) && i == ndev->num_msix - 1) - free_irq(msix->vector, ndev); - else - free_irq(msix->vector, &ndev->db_cb[i]); - } - pci_disable_msix(pdev); - kfree(ndev->msix_entries); - } else { - free_irq(pdev->irq, ndev); - - if (pci_dev_msi_enabled(pdev)) - pci_disable_msi(pdev); - } -} - -static int ntb_create_callbacks(struct ntb_device *ndev) -{ - int i; - - /* Chicken-egg issue. We won't know how many callbacks are necessary - * until we see how many MSI-X vectors we get, but these pointers need - * to be passed into the MSI-X register function. So, we allocate the - * max, knowing that they might not all be used, to work around this. - */ - ndev->db_cb = kcalloc(ndev->limits.max_db_bits, - sizeof(struct ntb_db_cb), - GFP_KERNEL); - if (!ndev->db_cb) - return -ENOMEM; - - for (i = 0; i < ndev->limits.max_db_bits; i++) { - ndev->db_cb[i].db_num = i; - ndev->db_cb[i].ndev = ndev; - } - - return 0; -} - -static void ntb_free_callbacks(struct ntb_device *ndev) -{ - int i; - - for (i = 0; i < ndev->limits.max_db_bits; i++) - ntb_unregister_db_callback(ndev, i); - - kfree(ndev->db_cb); -} - -static ssize_t ntb_debugfs_read(struct file *filp, char __user *ubuf, - size_t count, loff_t *offp) -{ - struct ntb_device *ndev; - char *buf; - ssize_t ret, offset, out_count; - - out_count = 500; - - buf = kmalloc(out_count, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - ndev = filp->private_data; - offset = 0; - offset += snprintf(buf + offset, out_count - offset, - "NTB Device Information:\n"); - offset += snprintf(buf + offset, out_count - offset, - "Connection Type - \t\t%s\n", - ndev->conn_type == NTB_CONN_TRANSPARENT ? - "Transparent" : (ndev->conn_type == NTB_CONN_B2B) ? - "Back to back" : "Root Port"); - offset += snprintf(buf + offset, out_count - offset, - "Device Type - \t\t\t%s\n", - ndev->dev_type == NTB_DEV_USD ? - "DSD/USP" : "USD/DSP"); - offset += snprintf(buf + offset, out_count - offset, - "Max Number of Callbacks - \t%u\n", - ntb_max_cbs(ndev)); - offset += snprintf(buf + offset, out_count - offset, - "Link Status - \t\t\t%s\n", - ntb_hw_link_status(ndev) ? "Up" : "Down"); - if (ntb_hw_link_status(ndev)) { - offset += snprintf(buf + offset, out_count - offset, - "Link Speed - \t\t\tPCI-E Gen %u\n", - ndev->link_speed); - offset += snprintf(buf + offset, out_count - offset, - "Link Width - \t\t\tx%u\n", - ndev->link_width); - } - - if (is_ntb_xeon(ndev)) { - u32 status32; - u16 status16; - int rc; - - offset += snprintf(buf + offset, out_count - offset, - "\nNTB Device Statistics:\n"); - offset += snprintf(buf + offset, out_count - offset, - "Upstream Memory Miss - \t%u\n", - readw(ndev->reg_base + - SNB_USMEMMISS_OFFSET)); - - offset += snprintf(buf + offset, out_count - offset, - "\nNTB Hardware Errors:\n"); - - rc = pci_read_config_word(ndev->pdev, SNB_DEVSTS_OFFSET, - &status16); - if (!rc) - offset += snprintf(buf + offset, out_count - offset, - "DEVSTS - \t%#06x\n", status16); - - rc = pci_read_config_word(ndev->pdev, SNB_LINK_STATUS_OFFSET, - &status16); - if (!rc) - offset += snprintf(buf + offset, out_count - offset, - "LNKSTS - \t%#06x\n", status16); - - rc = pci_read_config_dword(ndev->pdev, SNB_UNCERRSTS_OFFSET, - &status32); - if (!rc) - offset += snprintf(buf + offset, out_count - offset, - "UNCERRSTS - \t%#010x\n", status32); - - rc = pci_read_config_dword(ndev->pdev, SNB_CORERRSTS_OFFSET, - &status32); - if (!rc) - offset += snprintf(buf + offset, out_count - offset, - "CORERRSTS - \t%#010x\n", status32); - } - - if (offset > out_count) - offset = out_count; - - ret = simple_read_from_buffer(ubuf, count, offp, buf, offset); - kfree(buf); - return ret; -} - -static const struct file_operations ntb_debugfs_info = { - .owner = THIS_MODULE, - .open = simple_open, - .read = ntb_debugfs_read, -}; - -static void ntb_setup_debugfs(struct ntb_device *ndev) -{ - if (!debugfs_initialized()) - return; - - if (!debugfs_dir) - debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL); - - ndev->debugfs_dir = debugfs_create_dir(pci_name(ndev->pdev), - debugfs_dir); - if (ndev->debugfs_dir) - ndev->debugfs_info = debugfs_create_file("info", S_IRUSR, - ndev->debugfs_dir, - ndev, - &ntb_debugfs_info); -} - -static void ntb_free_debugfs(struct ntb_device *ndev) -{ - debugfs_remove_recursive(ndev->debugfs_dir); - - if (debugfs_dir && simple_empty(debugfs_dir)) { - debugfs_remove_recursive(debugfs_dir); - debugfs_dir = NULL; - } -} - -static void ntb_hw_link_up(struct ntb_device *ndev) -{ - if (ndev->conn_type == NTB_CONN_TRANSPARENT) - ntb_link_event(ndev, NTB_LINK_UP); - else { - u32 ntb_cntl; - - /* Let's bring the NTB link up */ - ntb_cntl = readl(ndev->reg_ofs.lnk_cntl); - ntb_cntl &= ~(NTB_CNTL_LINK_DISABLE | NTB_CNTL_CFG_LOCK); - ntb_cntl |= NTB_CNTL_P2S_BAR23_SNOOP | NTB_CNTL_S2P_BAR23_SNOOP; - ntb_cntl |= NTB_CNTL_P2S_BAR4_SNOOP | NTB_CNTL_S2P_BAR4_SNOOP; - if (ndev->split_bar) - ntb_cntl |= NTB_CNTL_P2S_BAR5_SNOOP | - NTB_CNTL_S2P_BAR5_SNOOP; - - writel(ntb_cntl, ndev->reg_ofs.lnk_cntl); - } -} - -static void ntb_hw_link_down(struct ntb_device *ndev) -{ - u32 ntb_cntl; - - if (ndev->conn_type == NTB_CONN_TRANSPARENT) { - ntb_link_event(ndev, NTB_LINK_DOWN); - return; - } - - /* Bring NTB link down */ - ntb_cntl = readl(ndev->reg_ofs.lnk_cntl); - ntb_cntl &= ~(NTB_CNTL_P2S_BAR23_SNOOP | NTB_CNTL_S2P_BAR23_SNOOP); - ntb_cntl &= ~(NTB_CNTL_P2S_BAR4_SNOOP | NTB_CNTL_S2P_BAR4_SNOOP); - if (ndev->split_bar) - ntb_cntl &= ~(NTB_CNTL_P2S_BAR5_SNOOP | - NTB_CNTL_S2P_BAR5_SNOOP); - ntb_cntl |= NTB_CNTL_LINK_DISABLE | NTB_CNTL_CFG_LOCK; - writel(ntb_cntl, ndev->reg_ofs.lnk_cntl); -} - -static void ntb_max_mw_detect(struct ntb_device *ndev) -{ - if (ndev->split_bar) - ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW; - else - ndev->limits.max_mw = SNB_MAX_MW; -} - -static int ntb_xeon_detect(struct ntb_device *ndev) -{ - int rc, bars_mask; - u32 bars; - u8 ppd; - - ndev->hw_type = SNB_HW; - - rc = pci_read_config_byte(ndev->pdev, NTB_PPD_OFFSET, &ppd); - if (rc) - return -EIO; - - if (ppd & SNB_PPD_DEV_TYPE) - ndev->dev_type = NTB_DEV_USD; - else - ndev->dev_type = NTB_DEV_DSD; - - ndev->split_bar = (ppd & SNB_PPD_SPLIT_BAR) ? 1 : 0; - - switch (ppd & SNB_PPD_CONN_TYPE) { - case NTB_CONN_B2B: - dev_info(&ndev->pdev->dev, "Conn Type = B2B\n"); - ndev->conn_type = NTB_CONN_B2B; - break; - case NTB_CONN_RP: - dev_info(&ndev->pdev->dev, "Conn Type = RP\n"); - ndev->conn_type = NTB_CONN_RP; - break; - case NTB_CONN_TRANSPARENT: - dev_info(&ndev->pdev->dev, "Conn Type = TRANSPARENT\n"); - ndev->conn_type = NTB_CONN_TRANSPARENT; - /* - * This mode is default to USD/DSP. HW does not report - * properly in transparent mode as it has no knowledge of - * NTB. We will just force correct here. - */ - ndev->dev_type = NTB_DEV_USD; - - /* - * This is a way for transparent BAR to figure out if we - * are doing split BAR or not. There is no way for the hw - * on the transparent side to know and set the PPD. - */ - bars_mask = pci_select_bars(ndev->pdev, IORESOURCE_MEM); - bars = hweight32(bars_mask); - if (bars == (HSX_SPLITBAR_MAX_MW + 1)) - ndev->split_bar = 1; - - break; - default: - dev_err(&ndev->pdev->dev, "Unknown PPD %x\n", ppd); - return -ENODEV; - } - - ntb_max_mw_detect(ndev); - - return 0; -} - -static int ntb_atom_detect(struct ntb_device *ndev) -{ - int rc; - u32 ppd; - - ndev->hw_type = BWD_HW; - ndev->limits.max_mw = BWD_MAX_MW; - - rc = pci_read_config_dword(ndev->pdev, NTB_PPD_OFFSET, &ppd); - if (rc) - return rc; - - switch ((ppd & BWD_PPD_CONN_TYPE) >> 8) { - case NTB_CONN_B2B: - dev_info(&ndev->pdev->dev, "Conn Type = B2B\n"); - ndev->conn_type = NTB_CONN_B2B; - break; - case NTB_CONN_RP: - default: - dev_err(&ndev->pdev->dev, "Unsupported NTB configuration\n"); - return -EINVAL; - } - - if (ppd & BWD_PPD_DEV_TYPE) - ndev->dev_type = NTB_DEV_DSD; - else - ndev->dev_type = NTB_DEV_USD; - - return 0; -} - -static int ntb_device_detect(struct ntb_device *ndev) -{ - int rc; - - if (is_ntb_xeon(ndev)) - rc = ntb_xeon_detect(ndev); - else if (is_ntb_atom(ndev)) - rc = ntb_atom_detect(ndev); - else - rc = -ENODEV; - - dev_info(&ndev->pdev->dev, "Device Type = %s\n", - ndev->dev_type == NTB_DEV_USD ? "USD/DSP" : "DSD/USP"); - - return 0; -} - -static int ntb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) -{ - struct ntb_device *ndev; - int rc, i; - - ndev = kzalloc(sizeof(struct ntb_device), GFP_KERNEL); - if (!ndev) - return -ENOMEM; - - ndev->pdev = pdev; - - ntb_set_errata_flags(ndev); - - ndev->link_status = NTB_LINK_DOWN; - pci_set_drvdata(pdev, ndev); - ntb_setup_debugfs(ndev); - - rc = pci_enable_device(pdev); - if (rc) - goto err; - - pci_set_master(ndev->pdev); - - rc = ntb_device_detect(ndev); - if (rc) - goto err; - - ndev->mw = kcalloc(ndev->limits.max_mw, sizeof(struct ntb_mw), - GFP_KERNEL); - if (!ndev->mw) { - rc = -ENOMEM; - goto err1; - } - - if (ndev->split_bar) - rc = pci_request_selected_regions(pdev, NTB_SPLITBAR_MASK, - KBUILD_MODNAME); - else - rc = pci_request_selected_regions(pdev, NTB_BAR_MASK, - KBUILD_MODNAME); - - if (rc) - goto err2; - - ndev->reg_base = pci_ioremap_bar(pdev, NTB_BAR_MMIO); - if (!ndev->reg_base) { - dev_warn(&pdev->dev, "Cannot remap BAR 0\n"); - rc = -EIO; - goto err3; - } - - for (i = 0; i < ndev->limits.max_mw; i++) { - ndev->mw[i].bar_sz = pci_resource_len(pdev, MW_TO_BAR(i)); - - /* - * with the errata we need to steal last of the memory - * windows for workarounds and they point to MMIO registers. - */ - if ((ndev->wa_flags & WA_SNB_ERR) && - (i == (ndev->limits.max_mw - 1))) { - ndev->mw[i].vbase = - ioremap_nocache(pci_resource_start(pdev, - MW_TO_BAR(i)), - ndev->mw[i].bar_sz); - } else { - ndev->mw[i].vbase = - ioremap_wc(pci_resource_start(pdev, - MW_TO_BAR(i)), - ndev->mw[i].bar_sz); - } - - dev_info(&pdev->dev, "MW %d size %llu\n", i, - (unsigned long long) ndev->mw[i].bar_sz); - if (!ndev->mw[i].vbase) { - dev_warn(&pdev->dev, "Cannot remap BAR %d\n", - MW_TO_BAR(i)); - rc = -EIO; - goto err4; - } - } - - rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); - if (rc) { - rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (rc) - goto err4; - - dev_warn(&pdev->dev, "Cannot DMA highmem\n"); - } - - rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); - if (rc) { - rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - if (rc) - goto err4; - - dev_warn(&pdev->dev, "Cannot DMA consistent highmem\n"); - } - - rc = ntb_device_setup(ndev); - if (rc) - goto err4; - - rc = ntb_create_callbacks(ndev); - if (rc) - goto err5; - - rc = ntb_setup_interrupts(ndev); - if (rc) - goto err6; - - /* The scratchpad registers keep the values between rmmod/insmod, - * blast them now - */ - for (i = 0; i < ndev->limits.max_spads; i++) { - ntb_write_local_spad(ndev, i, 0); - ntb_write_remote_spad(ndev, i, 0); - } - - rc = ntb_transport_init(pdev); - if (rc) - goto err7; - - ntb_hw_link_up(ndev); - - return 0; - -err7: - ntb_free_interrupts(ndev); -err6: - ntb_free_callbacks(ndev); -err5: - ntb_device_free(ndev); -err4: - for (i--; i >= 0; i--) - iounmap(ndev->mw[i].vbase); - iounmap(ndev->reg_base); -err3: - if (ndev->split_bar) - pci_release_selected_regions(pdev, NTB_SPLITBAR_MASK); - else - pci_release_selected_regions(pdev, NTB_BAR_MASK); -err2: - kfree(ndev->mw); -err1: - pci_disable_device(pdev); -err: - ntb_free_debugfs(ndev); - kfree(ndev); - - dev_err(&pdev->dev, "Error loading %s module\n", KBUILD_MODNAME); - return rc; -} - -static void ntb_pci_remove(struct pci_dev *pdev) -{ - struct ntb_device *ndev = pci_get_drvdata(pdev); - int i; - - ntb_hw_link_down(ndev); - - ntb_transport_free(ndev->ntb_transport); - - ntb_free_interrupts(ndev); - ntb_free_callbacks(ndev); - ntb_device_free(ndev); - - /* need to reset max_mw limits so we can unmap properly */ - if (ndev->hw_type == SNB_HW) - ntb_max_mw_detect(ndev); - - for (i = 0; i < ndev->limits.max_mw; i++) - iounmap(ndev->mw[i].vbase); - - kfree(ndev->mw); - iounmap(ndev->reg_base); - if (ndev->split_bar) - pci_release_selected_regions(pdev, NTB_SPLITBAR_MASK); - else - pci_release_selected_regions(pdev, NTB_BAR_MASK); - pci_disable_device(pdev); - ntb_free_debugfs(ndev); - kfree(ndev); -} - -static struct pci_driver ntb_pci_driver = { - .name = KBUILD_MODNAME, - .id_table = ntb_pci_tbl, - .probe = ntb_pci_probe, - .remove = ntb_pci_remove, -}; - -module_pci_driver(ntb_pci_driver); diff --git a/drivers/ntb/ntb_hw.h b/drivers/ntb/ntb_hw.h deleted file mode 100644 index 96de5fc95f90..000000000000 --- a/drivers/ntb/ntb_hw.h +++ /dev/null @@ -1,256 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2012 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * BSD LICENSE - * - * Copyright(c) 2012 Intel Corporation. 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 copy - * 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. - * - * Intel PCIe NTB Linux driver - * - * Contact Information: - * Jon Mason - */ -#include - -#define PCI_DEVICE_ID_INTEL_NTB_B2B_JSF 0x3725 -#define PCI_DEVICE_ID_INTEL_NTB_PS_JSF 0x3726 -#define PCI_DEVICE_ID_INTEL_NTB_SS_JSF 0x3727 -#define PCI_DEVICE_ID_INTEL_NTB_B2B_SNB 0x3C0D -#define PCI_DEVICE_ID_INTEL_NTB_PS_SNB 0x3C0E -#define PCI_DEVICE_ID_INTEL_NTB_SS_SNB 0x3C0F -#define PCI_DEVICE_ID_INTEL_NTB_B2B_IVT 0x0E0D -#define PCI_DEVICE_ID_INTEL_NTB_PS_IVT 0x0E0E -#define PCI_DEVICE_ID_INTEL_NTB_SS_IVT 0x0E0F -#define PCI_DEVICE_ID_INTEL_NTB_B2B_HSX 0x2F0D -#define PCI_DEVICE_ID_INTEL_NTB_PS_HSX 0x2F0E -#define PCI_DEVICE_ID_INTEL_NTB_SS_HSX 0x2F0F -#define PCI_DEVICE_ID_INTEL_NTB_B2B_BWD 0x0C4E - -#ifndef readq -static inline u64 readq(void __iomem *addr) -{ - return readl(addr) | (((u64) readl(addr + 4)) << 32LL); -} -#endif - -#ifndef writeq -static inline void writeq(u64 val, void __iomem *addr) -{ - writel(val & 0xffffffff, addr); - writel(val >> 32, addr + 4); -} -#endif - -#define NTB_BAR_MMIO 0 -#define NTB_BAR_23 2 -#define NTB_BAR_4 4 -#define NTB_BAR_5 5 - -#define NTB_BAR_MASK ((1 << NTB_BAR_MMIO) | (1 << NTB_BAR_23) |\ - (1 << NTB_BAR_4)) -#define NTB_SPLITBAR_MASK ((1 << NTB_BAR_MMIO) | (1 << NTB_BAR_23) |\ - (1 << NTB_BAR_4) | (1 << NTB_BAR_5)) - -#define NTB_HB_TIMEOUT msecs_to_jiffies(1000) - -enum ntb_hw_event { - NTB_EVENT_SW_EVENT0 = 0, - NTB_EVENT_SW_EVENT1, - NTB_EVENT_SW_EVENT2, - NTB_EVENT_HW_ERROR, - NTB_EVENT_HW_LINK_UP, - NTB_EVENT_HW_LINK_DOWN, -}; - -struct ntb_mw { - dma_addr_t phys_addr; - void __iomem *vbase; - resource_size_t bar_sz; -}; - -struct ntb_db_cb { - int (*callback)(void *data, int db_num); - unsigned int db_num; - void *data; - struct ntb_device *ndev; - struct tasklet_struct irq_work; -}; - -#define WA_SNB_ERR 0x00000001 - -struct ntb_device { - struct pci_dev *pdev; - struct msix_entry *msix_entries; - void __iomem *reg_base; - struct ntb_mw *mw; - struct { - unsigned char max_mw; - unsigned char max_spads; - unsigned char max_db_bits; - unsigned char msix_cnt; - } limits; - struct { - void __iomem *ldb; - void __iomem *ldb_mask; - void __iomem *rdb; - void __iomem *bar2_xlat; - void __iomem *bar4_xlat; - void __iomem *bar5_xlat; - void __iomem *spad_write; - void __iomem *spad_read; - void __iomem *lnk_cntl; - void __iomem *lnk_stat; - void __iomem *spci_cmd; - } reg_ofs; - struct ntb_transport *ntb_transport; - void (*event_cb)(void *handle, enum ntb_hw_event event); - - struct ntb_db_cb *db_cb; - unsigned char hw_type; - unsigned char conn_type; - unsigned char dev_type; - unsigned char num_msix; - unsigned char bits_per_vector; - unsigned char max_cbs; - unsigned char link_width; - unsigned char link_speed; - unsigned char link_status; - unsigned char split_bar; - - struct delayed_work hb_timer; - unsigned long last_ts; - - struct delayed_work lr_timer; - - struct dentry *debugfs_dir; - struct dentry *debugfs_info; - - unsigned int wa_flags; -}; - -/** - * ntb_max_cbs() - return the max callbacks - * @ndev: pointer to ntb_device instance - * - * Given the ntb pointer, return the maximum number of callbacks - * - * RETURNS: the maximum number of callbacks - */ -static inline unsigned char ntb_max_cbs(struct ntb_device *ndev) -{ - return ndev->max_cbs; -} - -/** - * ntb_max_mw() - return the max number of memory windows - * @ndev: pointer to ntb_device instance - * - * Given the ntb pointer, return the maximum number of memory windows - * - * RETURNS: the maximum number of memory windows - */ -static inline unsigned char ntb_max_mw(struct ntb_device *ndev) -{ - return ndev->limits.max_mw; -} - -/** - * ntb_hw_link_status() - return the hardware link status - * @ndev: pointer to ntb_device instance - * - * Returns true if the hardware is connected to the remote system - * - * RETURNS: true or false based on the hardware link state - */ -static inline bool ntb_hw_link_status(struct ntb_device *ndev) -{ - return ndev->link_status == NTB_LINK_UP; -} - -/** - * ntb_query_pdev() - return the pci_dev pointer - * @ndev: pointer to ntb_device instance - * - * Given the ntb pointer, return the pci_dev pointer for the NTB hardware device - * - * RETURNS: a pointer to the ntb pci_dev - */ -static inline struct pci_dev *ntb_query_pdev(struct ntb_device *ndev) -{ - return ndev->pdev; -} - -/** - * ntb_query_debugfs() - return the debugfs pointer - * @ndev: pointer to ntb_device instance - * - * Given the ntb pointer, return the debugfs directory pointer for the NTB - * hardware device - * - * RETURNS: a pointer to the debugfs directory - */ -static inline struct dentry *ntb_query_debugfs(struct ntb_device *ndev) -{ - return ndev->debugfs_dir; -} - -struct ntb_device *ntb_register_transport(struct pci_dev *pdev, - void *transport); -void ntb_unregister_transport(struct ntb_device *ndev); -void ntb_set_mw_addr(struct ntb_device *ndev, unsigned int mw, u64 addr); -int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx, - void *data, int (*db_cb_func)(void *data, - int db_num)); -void ntb_unregister_db_callback(struct ntb_device *ndev, unsigned int idx); -int ntb_register_event_callback(struct ntb_device *ndev, - void (*event_cb_func)(void *handle, - enum ntb_hw_event event)); -void ntb_unregister_event_callback(struct ntb_device *ndev); -int ntb_get_max_spads(struct ntb_device *ndev); -int ntb_write_local_spad(struct ntb_device *ndev, unsigned int idx, u32 val); -int ntb_read_local_spad(struct ntb_device *ndev, unsigned int idx, u32 *val); -int ntb_write_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 val); -int ntb_read_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 *val); -resource_size_t ntb_get_mw_base(struct ntb_device *ndev, unsigned int mw); -void __iomem *ntb_get_mw_vbase(struct ntb_device *ndev, unsigned int mw); -u64 ntb_get_mw_size(struct ntb_device *ndev, unsigned int mw); -void ntb_ring_doorbell(struct ntb_device *ndev, unsigned int idx); -void *ntb_find_transport(struct pci_dev *pdev); - -int ntb_transport_init(struct pci_dev *pdev); -void ntb_transport_free(void *transport); diff --git a/drivers/ntb/ntb_regs.h b/drivers/ntb/ntb_regs.h deleted file mode 100644 index f028ff81fd77..000000000000 --- a/drivers/ntb/ntb_regs.h +++ /dev/null @@ -1,177 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2012 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * BSD LICENSE - * - * Copyright(c) 2012 Intel Corporation. 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 copy - * 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. - * - * Intel PCIe NTB Linux driver - * - * Contact Information: - * Jon Mason - */ - -#define NTB_LINK_STATUS_ACTIVE 0x2000 -#define NTB_LINK_SPEED_MASK 0x000f -#define NTB_LINK_WIDTH_MASK 0x03f0 - -#define SNB_MSIX_CNT 4 -#define SNB_MAX_B2B_SPADS 16 -#define SNB_MAX_COMPAT_SPADS 16 -/* Reserve the uppermost bit for link interrupt */ -#define SNB_MAX_DB_BITS 15 -#define SNB_LINK_DB 15 -#define SNB_DB_BITS_PER_VEC 5 -#define HSX_SPLITBAR_MAX_MW 3 -#define SNB_MAX_MW 2 -#define SNB_ERRATA_MAX_MW 1 - -#define SNB_DB_HW_LINK 0x8000 - -#define SNB_UNCERRSTS_OFFSET 0x014C -#define SNB_CORERRSTS_OFFSET 0x0158 -#define SNB_LINK_STATUS_OFFSET 0x01A2 -#define SNB_PCICMD_OFFSET 0x0504 -#define SNB_DEVCTRL_OFFSET 0x0598 -#define SNB_DEVSTS_OFFSET 0x059A -#define SNB_SLINK_STATUS_OFFSET 0x05A2 - -#define SNB_PBAR2LMT_OFFSET 0x0000 -#define SNB_PBAR4LMT_OFFSET 0x0008 -#define SNB_PBAR5LMT_OFFSET 0x000C -#define SNB_PBAR2XLAT_OFFSET 0x0010 -#define SNB_PBAR4XLAT_OFFSET 0x0018 -#define SNB_PBAR5XLAT_OFFSET 0x001C -#define SNB_SBAR2LMT_OFFSET 0x0020 -#define SNB_SBAR4LMT_OFFSET 0x0028 -#define SNB_SBAR5LMT_OFFSET 0x002C -#define SNB_SBAR2XLAT_OFFSET 0x0030 -#define SNB_SBAR4XLAT_OFFSET 0x0038 -#define SNB_SBAR5XLAT_OFFSET 0x003C -#define SNB_SBAR0BASE_OFFSET 0x0040 -#define SNB_SBAR2BASE_OFFSET 0x0048 -#define SNB_SBAR4BASE_OFFSET 0x0050 -#define SNB_SBAR5BASE_OFFSET 0x0054 -#define SNB_NTBCNTL_OFFSET 0x0058 -#define SNB_SBDF_OFFSET 0x005C -#define SNB_PDOORBELL_OFFSET 0x0060 -#define SNB_PDBMSK_OFFSET 0x0062 -#define SNB_SDOORBELL_OFFSET 0x0064 -#define SNB_SDBMSK_OFFSET 0x0066 -#define SNB_USMEMMISS_OFFSET 0x0070 -#define SNB_SPAD_OFFSET 0x0080 -#define SNB_SPADSEMA4_OFFSET 0x00c0 -#define SNB_WCCNTRL_OFFSET 0x00e0 -#define SNB_B2B_SPAD_OFFSET 0x0100 -#define SNB_B2B_DOORBELL_OFFSET 0x0140 -#define SNB_B2B_XLAT_OFFSETL 0x0144 -#define SNB_B2B_XLAT_OFFSETU 0x0148 - -/* - * The addresses are setup so the 32bit BARs can function. Thus - * the addresses are all in 32bit space - */ -#define SNB_MBAR01_USD_ADDR 0x000000002100000CULL -#define SNB_MBAR23_USD_ADDR 0x000000004100000CULL -#define SNB_MBAR4_USD_ADDR 0x000000008100000CULL -#define SNB_MBAR5_USD_ADDR 0x00000000A100000CULL -#define SNB_MBAR01_DSD_ADDR 0x000000002000000CULL -#define SNB_MBAR23_DSD_ADDR 0x000000004000000CULL -#define SNB_MBAR4_DSD_ADDR 0x000000008000000CULL -#define SNB_MBAR5_DSD_ADDR 0x00000000A000000CULL - -#define BWD_MSIX_CNT 34 -#define BWD_MAX_SPADS 16 -#define BWD_MAX_DB_BITS 34 -#define BWD_DB_BITS_PER_VEC 1 -#define BWD_MAX_MW 2 - -#define BWD_PCICMD_OFFSET 0xb004 -#define BWD_MBAR23_OFFSET 0xb018 -#define BWD_MBAR45_OFFSET 0xb020 -#define BWD_DEVCTRL_OFFSET 0xb048 -#define BWD_LINK_STATUS_OFFSET 0xb052 -#define BWD_ERRCORSTS_OFFSET 0xb110 - -#define BWD_SBAR2XLAT_OFFSET 0x0008 -#define BWD_SBAR4XLAT_OFFSET 0x0010 -#define BWD_PDOORBELL_OFFSET 0x0020 -#define BWD_PDBMSK_OFFSET 0x0028 -#define BWD_NTBCNTL_OFFSET 0x0060 -#define BWD_EBDF_OFFSET 0x0064 -#define BWD_SPAD_OFFSET 0x0080 -#define BWD_SPADSEMA_OFFSET 0x00c0 -#define BWD_STKYSPAD_OFFSET 0x00c4 -#define BWD_PBAR2XLAT_OFFSET 0x8008 -#define BWD_PBAR4XLAT_OFFSET 0x8010 -#define BWD_B2B_DOORBELL_OFFSET 0x8020 -#define BWD_B2B_SPAD_OFFSET 0x8080 -#define BWD_B2B_SPADSEMA_OFFSET 0x80c0 -#define BWD_B2B_STKYSPAD_OFFSET 0x80c4 - -#define BWD_MODPHY_PCSREG4 0x1c004 -#define BWD_MODPHY_PCSREG6 0x1c006 - -#define BWD_IP_BASE 0xC000 -#define BWD_DESKEWSTS_OFFSET (BWD_IP_BASE + 0x3024) -#define BWD_LTSSMERRSTS0_OFFSET (BWD_IP_BASE + 0x3180) -#define BWD_LTSSMSTATEJMP_OFFSET (BWD_IP_BASE + 0x3040) -#define BWD_IBSTERRRCRVSTS0_OFFSET (BWD_IP_BASE + 0x3324) - -#define BWD_DESKEWSTS_DBERR (1 << 15) -#define BWD_LTSSMERRSTS0_UNEXPECTEDEI (1 << 20) -#define BWD_LTSSMSTATEJMP_FORCEDETECT (1 << 2) -#define BWD_IBIST_ERR_OFLOW 0x7FFF7FFF - -#define NTB_CNTL_CFG_LOCK (1 << 0) -#define NTB_CNTL_LINK_DISABLE (1 << 1) -#define NTB_CNTL_S2P_BAR23_SNOOP (1 << 2) -#define NTB_CNTL_P2S_BAR23_SNOOP (1 << 4) -#define NTB_CNTL_S2P_BAR4_SNOOP (1 << 6) -#define NTB_CNTL_P2S_BAR4_SNOOP (1 << 8) -#define NTB_CNTL_S2P_BAR5_SNOOP (1 << 12) -#define NTB_CNTL_P2S_BAR5_SNOOP (1 << 14) -#define BWD_CNTL_LINK_DOWN (1 << 16) - -#define NTB_PPD_OFFSET 0x00D4 -#define SNB_PPD_CONN_TYPE 0x0003 -#define SNB_PPD_DEV_TYPE 0x0010 -#define SNB_PPD_SPLIT_BAR (1 << 6) -#define BWD_PPD_INIT_LINK 0x0008 -#define BWD_PPD_CONN_TYPE 0x0300 -#define BWD_PPD_DEV_TYPE 0x1000 diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index e9bf2f47b61a..c5f26cda9f97 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c @@ -56,7 +56,7 @@ #include #include #include -#include "ntb_hw.h" +#include "hw/intel/ntb_hw_intel.h" #define NTB_TRANSPORT_VERSION 3 @@ -360,14 +360,14 @@ err: EXPORT_SYMBOL_GPL(ntb_register_client_dev); /** - * ntb_register_client - Register NTB client driver + * ntb_transport_register_client - Register NTB client driver * @drv: NTB client driver to be registered * * Register an NTB client driver with the NTB transport layer * * RETURNS: An appropriate -ERRNO error value on error, or zero for success. */ -int ntb_register_client(struct ntb_client *drv) +int ntb_transport_register_client(struct ntb_client *drv) { drv->driver.bus = &ntb_bus_type; @@ -376,21 +376,21 @@ int ntb_register_client(struct ntb_client *drv) return driver_register(&drv->driver); } -EXPORT_SYMBOL_GPL(ntb_register_client); +EXPORT_SYMBOL_GPL(ntb_transport_register_client); /** - * ntb_unregister_client - Unregister NTB client driver + * ntb_transport_unregister_client - Unregister NTB client driver * @drv: NTB client driver to be unregistered * * Unregister an NTB client driver with the NTB transport layer * * RETURNS: An appropriate -ERRNO error value on error, or zero for success. */ -void ntb_unregister_client(struct ntb_client *drv) +void ntb_transport_unregister_client(struct ntb_client *drv) { driver_unregister(&drv->driver); } -EXPORT_SYMBOL_GPL(ntb_unregister_client); +EXPORT_SYMBOL_GPL(ntb_transport_unregister_client); static ssize_t debugfs_read(struct file *filp, char __user *ubuf, size_t count, loff_t *offp) diff --git a/include/linux/ntb.h b/include/linux/ntb.h deleted file mode 100644 index 9ac1a62fc6f5..000000000000 --- a/include/linux/ntb.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2012 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * BSD LICENSE - * - * Copyright(c) 2012 Intel Corporation. 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 copy - * 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. - * - * Intel PCIe NTB Linux driver - * - * Contact Information: - * Jon Mason - */ - -struct ntb_transport_qp; - -struct ntb_client { - struct device_driver driver; - int (*probe)(struct pci_dev *pdev); - void (*remove)(struct pci_dev *pdev); -}; - -enum { - NTB_LINK_DOWN = 0, - NTB_LINK_UP, -}; - -int ntb_register_client(struct ntb_client *drvr); -void ntb_unregister_client(struct ntb_client *drvr); -int ntb_register_client_dev(char *device_name); -void ntb_unregister_client_dev(char *device_name); - -struct ntb_queue_handlers { - void (*rx_handler)(struct ntb_transport_qp *qp, void *qp_data, - void *data, int len); - void (*tx_handler)(struct ntb_transport_qp *qp, void *qp_data, - void *data, int len); - void (*event_handler)(void *data, int status); -}; - -unsigned char ntb_transport_qp_num(struct ntb_transport_qp *qp); -unsigned int ntb_transport_max_size(struct ntb_transport_qp *qp); -struct ntb_transport_qp * -ntb_transport_create_queue(void *data, struct pci_dev *pdev, - const struct ntb_queue_handlers *handlers); -void ntb_transport_free_queue(struct ntb_transport_qp *qp); -int ntb_transport_rx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data, - unsigned int len); -int ntb_transport_tx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data, - unsigned int len); -void *ntb_transport_rx_remove(struct ntb_transport_qp *qp, unsigned int *len); -void ntb_transport_link_up(struct ntb_transport_qp *qp); -void ntb_transport_link_down(struct ntb_transport_qp *qp); -bool ntb_transport_link_query(struct ntb_transport_qp *qp); diff --git a/include/linux/ntb_transport.h b/include/linux/ntb_transport.h new file mode 100644 index 000000000000..f78b64cc09d5 --- /dev/null +++ b/include/linux/ntb_transport.h @@ -0,0 +1,88 @@ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2012 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * BSD LICENSE + * + * Copyright(c) 2012 Intel Corporation. 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 copy + * 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. + * + * Intel PCIe NTB Linux driver + * + * Contact Information: + * Jon Mason + */ + +struct ntb_transport_qp; + +struct ntb_client { + struct device_driver driver; + int (*probe)(struct pci_dev *pdev); + void (*remove)(struct pci_dev *pdev); +}; + +enum { + NTB_LINK_DOWN = 0, + NTB_LINK_UP, +}; + +int ntb_transport_register_client(struct ntb_client *drvr); +void ntb_transport_unregister_client(struct ntb_client *drvr); +int ntb_register_client_dev(char *device_name); +void ntb_unregister_client_dev(char *device_name); + +struct ntb_queue_handlers { + void (*rx_handler)(struct ntb_transport_qp *qp, void *qp_data, + void *data, int len); + void (*tx_handler)(struct ntb_transport_qp *qp, void *qp_data, + void *data, int len); + void (*event_handler)(void *data, int status); +}; + +unsigned char ntb_transport_qp_num(struct ntb_transport_qp *qp); +unsigned int ntb_transport_max_size(struct ntb_transport_qp *qp); +struct ntb_transport_qp * +ntb_transport_create_queue(void *data, struct pci_dev *pdev, + const struct ntb_queue_handlers *handlers); +void ntb_transport_free_queue(struct ntb_transport_qp *qp); +int ntb_transport_rx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data, + unsigned int len); +int ntb_transport_tx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data, + unsigned int len); +void *ntb_transport_rx_remove(struct ntb_transport_qp *qp, unsigned int *len); +void ntb_transport_link_up(struct ntb_transport_qp *qp); +void ntb_transport_link_down(struct ntb_transport_qp *qp); +bool ntb_transport_link_query(struct ntb_transport_qp *qp); -- cgit v1.2.3-70-g09d2 From 758dd7fdffd60507624edce34fff122a63163b3f Mon Sep 17 00:00:00 2001 From: Jon Derrick Date: Tue, 30 Jun 2015 11:22:52 -0600 Subject: NVMe: Fix irq freeing when queue_request_irq fails Fixes an issue when queue_reuest_irq fails in nvme_setup_io_queues. This patch initializes all vectors to -1 and resets the vector to -1 in the case of a failure in queue_request_irq. This avoids the free_irq in nvme_suspend_queue if the queue did not get an irq. Signed-off-by: Jon Derrick Signed-off-by: Jens Axboe --- drivers/block/nvme-core.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index 34338d7438f5..d1d6141920d3 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -1474,6 +1474,7 @@ static struct nvme_queue *nvme_alloc_queue(struct nvme_dev *dev, int qid, nvmeq->q_db = &dev->dbs[qid * 2 * dev->db_stride]; nvmeq->q_depth = depth; nvmeq->qid = qid; + nvmeq->cq_vector = -1; dev->queues[qid] = nvmeq; /* make sure queue descriptor is set before queue count, for kthread */ @@ -1726,8 +1727,10 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev) nvmeq->cq_vector = 0; result = queue_request_irq(dev, nvmeq, nvmeq->irqname); - if (result) + if (result) { + nvmeq->cq_vector = -1; goto free_nvmeq; + } return result; @@ -2213,8 +2216,10 @@ static int nvme_setup_io_queues(struct nvme_dev *dev) dev->max_qid = nr_io_queues; result = queue_request_irq(dev, adminq, adminq->irqname); - if (result) + if (result) { + adminq->cq_vector = -1; goto free_queues; + } /* Free previously allocated queues that are no longer usable */ nvme_free_queues(dev, nr_io_queues + 1); -- cgit v1.2.3-70-g09d2 From 45a481c2176f6acca2efb6477c6018b2c3e3c60f Mon Sep 17 00:00:00 2001 From: Ray Jui Date: Mon, 29 Jun 2015 14:30:09 -0700 Subject: clk: iproc: fix memory leak from clock name of_property_read_string_index takes array of pointers and assign them to strings read from device tree property. No additional memory allocation is needed prior to calling of_property_read_string_index. In fact, since the array of pointers will be re-assigned to other strings, any memory that it points to prior to calling of_property_read_string_index will be leaked Reported-by: Dan Carpenter Signed-off-by: Ray Jui Fixes: 5fe225c105fd ("clk: iproc: add initial common clock support") Signed-off-by: Stephen Boyd --- drivers/clk/bcm/clk-iproc-asiu.c | 6 +----- drivers/clk/bcm/clk-iproc-pll.c | 8 +------- 2 files changed, 2 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/bcm/clk-iproc-asiu.c b/drivers/clk/bcm/clk-iproc-asiu.c index e19c09cd9645..f630e1bbdcfe 100644 --- a/drivers/clk/bcm/clk-iproc-asiu.c +++ b/drivers/clk/bcm/clk-iproc-asiu.c @@ -222,10 +222,6 @@ void __init iproc_asiu_setup(struct device_node *node, struct iproc_asiu_clk *asiu_clk; const char *clk_name; - clk_name = kzalloc(IPROC_CLK_NAME_LEN, GFP_KERNEL); - if (WARN_ON(!clk_name)) - goto err_clk_register; - ret = of_property_read_string_index(node, "clock-output-names", i, &clk_name); if (WARN_ON(ret)) @@ -259,7 +255,7 @@ void __init iproc_asiu_setup(struct device_node *node, err_clk_register: for (i = 0; i < num_clks; i++) - kfree(asiu->clks[i].name); + clk_unregister(asiu->clk_data.clks[i]); iounmap(asiu->gate_base); err_iomap_gate: diff --git a/drivers/clk/bcm/clk-iproc-pll.c b/drivers/clk/bcm/clk-iproc-pll.c index 46fb84bc2674..a8d971b820b0 100644 --- a/drivers/clk/bcm/clk-iproc-pll.c +++ b/drivers/clk/bcm/clk-iproc-pll.c @@ -655,10 +655,6 @@ void __init iproc_pll_clk_setup(struct device_node *node, memset(&init, 0, sizeof(init)); parent_name = node->name; - clk_name = kzalloc(IPROC_CLK_NAME_LEN, GFP_KERNEL); - if (WARN_ON(!clk_name)) - goto err_clk_register; - ret = of_property_read_string_index(node, "clock-output-names", i, &clk_name); if (WARN_ON(ret)) @@ -690,10 +686,8 @@ void __init iproc_pll_clk_setup(struct device_node *node, return; err_clk_register: - for (i = 0; i < num_clks; i++) { - kfree(pll->clks[i].name); + for (i = 0; i < num_clks; i++) clk_unregister(pll->clk_data.clks[i]); - } err_pll_register: if (pll->asiu_base) -- cgit v1.2.3-70-g09d2 From 69916d96094e1e16567c5f25515a13ed2896c730 Mon Sep 17 00:00:00 2001 From: Ray Jui Date: Mon, 29 Jun 2015 14:30:10 -0700 Subject: clk: iproc: fix bit manipulation arithmetic A 32-bit variable should be type casted to 64-bit before arithmetic operation and assigning it to a 64-bit variable Reported-by: Dan Carpenter Signed-off-by: Ray Jui Fixes: 5fe225c105fd ("clk: iproc: add initial common clock support") Signed-off-by: Stephen Boyd --- drivers/clk/bcm/clk-iproc-pll.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/bcm/clk-iproc-pll.c b/drivers/clk/bcm/clk-iproc-pll.c index a8d971b820b0..2dda4e8295a9 100644 --- a/drivers/clk/bcm/clk-iproc-pll.c +++ b/drivers/clk/bcm/clk-iproc-pll.c @@ -366,7 +366,7 @@ static unsigned long iproc_pll_recalc_rate(struct clk_hw *hw, val = readl(pll->pll_base + ctrl->ndiv_int.offset); ndiv_int = (val >> ctrl->ndiv_int.shift) & bit_mask(ctrl->ndiv_int.width); - ndiv = ndiv_int << ctrl->ndiv_int.shift; + ndiv = (u64)ndiv_int << ctrl->ndiv_int.shift; if (ctrl->flags & IPROC_CLK_PLL_HAS_NDIV_FRAC) { val = readl(pll->pll_base + ctrl->ndiv_frac.offset); @@ -374,7 +374,8 @@ static unsigned long iproc_pll_recalc_rate(struct clk_hw *hw, bit_mask(ctrl->ndiv_frac.width); if (ndiv_frac != 0) - ndiv = (ndiv_int << ctrl->ndiv_int.shift) | ndiv_frac; + ndiv = ((u64)ndiv_int << ctrl->ndiv_int.shift) | + ndiv_frac; } val = readl(pll->pll_base + ctrl->pdiv.offset); -- cgit v1.2.3-70-g09d2 From 15ab38273d21a45487116ad4c428593427954848 Mon Sep 17 00:00:00 2001 From: Daniel Thompson Date: Sun, 28 Jun 2015 10:55:32 +0100 Subject: clk: stm32: Fix out-by-one error path in the index lookup If stm32f4_rcc_lookup() is called with primary == 0 and secondary == 192 then it will read beyond the end of the table array due to an out-by-one error in the range check. In addition to the fixing the inequality we also modify the r.h.s. to make it even more explicit that we are comparing against the size of table in bits. Reported-by: Dan Carpenter Signed-off-by: Daniel Thompson Acked-by: Maxime Coquelin Fixes: 358bdf892f6b ("clk: stm32: Add clock driver for STM32F4[23]xxx devices") Signed-off-by: Stephen Boyd --- drivers/clk/clk-stm32f4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/clk-stm32f4.c b/drivers/clk/clk-stm32f4.c index b9b12a742970..3f6f7ad39490 100644 --- a/drivers/clk/clk-stm32f4.c +++ b/drivers/clk/clk-stm32f4.c @@ -268,7 +268,7 @@ static int stm32f4_rcc_lookup_clk_idx(u8 primary, u8 secondary) memcpy(table, stm32f42xx_gate_map, sizeof(table)); /* only bits set in table can be used as indices */ - if (WARN_ON(secondary > 8 * sizeof(table) || + if (WARN_ON(secondary >= BITS_PER_BYTE * sizeof(table) || 0 == (table[BIT_ULL_WORD(secondary)] & BIT_ULL_MASK(secondary)))) return -EINVAL; -- cgit v1.2.3-70-g09d2 From c76a024e82bdb83a0f7d57e006f8e7f8ddf983e5 Mon Sep 17 00:00:00 2001 From: David Dueck Date: Fri, 26 Jun 2015 15:30:22 +0200 Subject: clk: at91: do not leak resources Do not leak memory and free irqs in case of an error. Acked-by: Boris Brezillon Signed-off-by: David Dueck Signed-off-by: Stephen Boyd --- drivers/clk/at91/clk-h32mx.c | 4 +++- drivers/clk/at91/clk-main.c | 4 +++- drivers/clk/at91/clk-master.c | 8 ++++++-- drivers/clk/at91/clk-pll.c | 8 ++++++-- drivers/clk/at91/clk-system.c | 8 ++++++-- drivers/clk/at91/clk-utmi.c | 8 ++++++-- 6 files changed, 30 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/at91/clk-h32mx.c b/drivers/clk/at91/clk-h32mx.c index 152dcb3f7b5f..61566bcefa53 100644 --- a/drivers/clk/at91/clk-h32mx.c +++ b/drivers/clk/at91/clk-h32mx.c @@ -116,8 +116,10 @@ void __init of_sama5d4_clk_h32mx_setup(struct device_node *np, h32mxclk->pmc = pmc; clk = clk_register(NULL, &h32mxclk->hw); - if (!clk) + if (!clk) { + kfree(h32mxclk); return; + } of_clk_add_provider(np, of_clk_src_simple_get, clk); } diff --git a/drivers/clk/at91/clk-main.c b/drivers/clk/at91/clk-main.c index c2400456a044..27dfa965cfed 100644 --- a/drivers/clk/at91/clk-main.c +++ b/drivers/clk/at91/clk-main.c @@ -171,8 +171,10 @@ at91_clk_register_main_osc(struct at91_pmc *pmc, irq_set_status_flags(osc->irq, IRQ_NOAUTOEN); ret = request_irq(osc->irq, clk_main_osc_irq_handler, IRQF_TRIGGER_HIGH, name, osc); - if (ret) + if (ret) { + kfree(osc); return ERR_PTR(ret); + } if (bypass) pmc_write(pmc, AT91_CKGR_MOR, diff --git a/drivers/clk/at91/clk-master.c b/drivers/clk/at91/clk-master.c index f98eafe9b12d..5b3ded5205a2 100644 --- a/drivers/clk/at91/clk-master.c +++ b/drivers/clk/at91/clk-master.c @@ -165,12 +165,16 @@ at91_clk_register_master(struct at91_pmc *pmc, unsigned int irq, irq_set_status_flags(master->irq, IRQ_NOAUTOEN); ret = request_irq(master->irq, clk_master_irq_handler, IRQF_TRIGGER_HIGH, "clk-master", master); - if (ret) + if (ret) { + kfree(master); return ERR_PTR(ret); + } clk = clk_register(NULL, &master->hw); - if (IS_ERR(clk)) + if (IS_ERR(clk)) { + free_irq(master->irq, master); kfree(master); + } return clk; } diff --git a/drivers/clk/at91/clk-pll.c b/drivers/clk/at91/clk-pll.c index 6ec79dbc0840..23163be24b6f 100644 --- a/drivers/clk/at91/clk-pll.c +++ b/drivers/clk/at91/clk-pll.c @@ -338,12 +338,16 @@ at91_clk_register_pll(struct at91_pmc *pmc, unsigned int irq, const char *name, irq_set_status_flags(pll->irq, IRQ_NOAUTOEN); ret = request_irq(pll->irq, clk_pll_irq_handler, IRQF_TRIGGER_HIGH, id ? "clk-pllb" : "clk-plla", pll); - if (ret) + if (ret) { + kfree(pll); return ERR_PTR(ret); + } clk = clk_register(NULL, &pll->hw); - if (IS_ERR(clk)) + if (IS_ERR(clk)) { + free_irq(pll->irq, pll); kfree(pll); + } return clk; } diff --git a/drivers/clk/at91/clk-system.c b/drivers/clk/at91/clk-system.c index a76d03fd577b..58008b3e8bc1 100644 --- a/drivers/clk/at91/clk-system.c +++ b/drivers/clk/at91/clk-system.c @@ -130,13 +130,17 @@ at91_clk_register_system(struct at91_pmc *pmc, const char *name, irq_set_status_flags(sys->irq, IRQ_NOAUTOEN); ret = request_irq(sys->irq, clk_system_irq_handler, IRQF_TRIGGER_HIGH, name, sys); - if (ret) + if (ret) { + kfree(sys); return ERR_PTR(ret); + } } clk = clk_register(NULL, &sys->hw); - if (IS_ERR(clk)) + if (IS_ERR(clk)) { + free_irq(sys->irq, sys); kfree(sys); + } return clk; } diff --git a/drivers/clk/at91/clk-utmi.c b/drivers/clk/at91/clk-utmi.c index ae3263bc1476..30dd697b1668 100644 --- a/drivers/clk/at91/clk-utmi.c +++ b/drivers/clk/at91/clk-utmi.c @@ -118,12 +118,16 @@ at91_clk_register_utmi(struct at91_pmc *pmc, unsigned int irq, irq_set_status_flags(utmi->irq, IRQ_NOAUTOEN); ret = request_irq(utmi->irq, clk_utmi_irq_handler, IRQF_TRIGGER_HIGH, "clk-utmi", utmi); - if (ret) + if (ret) { + kfree(utmi); return ERR_PTR(ret); + } clk = clk_register(NULL, &utmi->hw); - if (IS_ERR(clk)) + if (IS_ERR(clk)) { + free_irq(utmi->irq, utmi); kfree(utmi); + } return clk; } -- cgit v1.2.3-70-g09d2 From 91e20b5040c67c51aad88cf87db4305c5bd7f79d Mon Sep 17 00:00:00 2001 From: Joel Porquet Date: Thu, 2 Jul 2015 15:32:00 -0400 Subject: irqchip: Move IRQCHIP_DECLARE macro to include/linux/irqchip.h At the moment the IRQCHIP_DECLARE macro is only declared locally in drivers/irqchip/irqchip.h. It prevents from using it directly in arch/* directories whenever irqchip drivers only exist there, which happens in a few cases (e.g. arc, arm, microblaze and mips). This patch makes the macro to be globally defined, i.e. in include/linux/irqchip.h, and thus usable for arch-specific declarations of irqchip drivers. In this way, it is very similar to what clocksource does (ie CLOCKSOURCE_OF_DECLARE is defined in include/linux/clocksource.h). For now, this patch only moves the declaration of the macro IRQCHIP_DECLARE to the global header 'include/linux/irqchip.h' and make 'drivers/irqchip/irqchip.h' include 'include/linux/irqchip.h'. Later, other patches will get rid of 'drivers/irqchip/irqchip.h' and modify all the impacted irqchip drivers. Signed-off-by: Joel Porquet Cc: Jason Cooper Link: http://lkml.kernel.org/r/1435865565-14114-1-git-send-email-joel@porquet.org Signed-off-by: Thomas Gleixner --- drivers/irqchip/irqchip.h | 19 +------------------ include/linux/irqchip.h | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irqchip.h b/drivers/irqchip/irqchip.h index 0f6486d4f1b0..0f67ae32464f 100644 --- a/drivers/irqchip/irqchip.h +++ b/drivers/irqchip/irqchip.h @@ -8,21 +8,4 @@ * warranty of any kind, whether express or implied. */ -#ifndef _IRQCHIP_H -#define _IRQCHIP_H - -#include - -/* - * This macro must be used by the different irqchip drivers to declare - * the association between their DT compatible string and their - * initialization function. - * - * @name: name that must be unique accross all IRQCHIP_DECLARE of the - * same file. - * @compstr: compatible string of the irqchip driver - * @fn: initialization function - */ -#define IRQCHIP_DECLARE(name, compat, fn) OF_DECLARE_2(irqchip, name, compat, fn) - -#endif +#include diff --git a/include/linux/irqchip.h b/include/linux/irqchip.h index 14d79131f53d..638887376e58 100644 --- a/include/linux/irqchip.h +++ b/include/linux/irqchip.h @@ -11,6 +11,20 @@ #ifndef _LINUX_IRQCHIP_H #define _LINUX_IRQCHIP_H +#include + +/* + * This macro must be used by the different irqchip drivers to declare + * the association between their DT compatible string and their + * initialization function. + * + * @name: name that must be unique accross all IRQCHIP_DECLARE of the + * same file. + * @compstr: compatible string of the irqchip driver + * @fn: initialization function + */ +#define IRQCHIP_DECLARE(name, compat, fn) OF_DECLARE_2(irqchip, name, compat, fn) + #ifdef CONFIG_IRQCHIP void irqchip_init(void); #else -- cgit v1.2.3-70-g09d2 From 18d78b64fddc11eb336f01e46ad3303a3f55d039 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 3 Jul 2015 01:06:00 +0200 Subject: ACPI / init: Make it possible to override _REV The platform firmware on some systems expects Linux to return "5" as the supported ACPI revision which makes it expose system configuration information in a special way. For example, based on what ACPI exports as the supported revision, Dell XPS 13 (2015) configures its audio device to either work in HDA mode or in I2S mode, where the former is supposed to be used on Linux until the latter is fully supported (in the kernel as well as in user space). Since ACPI 6 mandates that _REV should return "2" if ACPI 2 or later is supported by the OS, a subsequent change will make that happen, so make it possible to override that on systems where "5" is expected to be returned for Linux to work correctly one them (such as the Dell machine mentioned above). Original-by: Dominik Brodowski Signed-off-by: Rafael J. Wysocki --- Documentation/kernel-parameters.txt | 6 ++++++ drivers/acpi/Kconfig | 20 ++++++++++++++++++++ drivers/acpi/blacklist.c | 26 ++++++++++++++++++++++++++ drivers/acpi/internal.h | 1 + drivers/acpi/osl.c | 18 ++++++++++++++++++ 5 files changed, 71 insertions(+) (limited to 'drivers') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 61ab1628a057..180102480fc0 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -274,6 +274,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted. acpi_os_name= [HW,ACPI] Tell ACPI BIOS the name of the OS Format: To spoof as Windows 98: ="Microsoft Windows" + acpi_rev_override [ACPI] Override the _REV object to return 5 (instead + of 2 which is mandated by ACPI 6) as the supported ACPI + specification revision (when using this switch, it may + be necessary to carry out a cold reboot _twice_ in a + row to make it take effect on the platform firmware). + acpi_osi= [HW,ACPI] Modify list of supported OS interface strings acpi_osi="string1" # add string1 acpi_osi="!string2" # remove string2 diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index ab2cbb51c6aa..2b652f1d4edb 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -77,6 +77,26 @@ config ACPI_PROCFS_POWER Say N to delete power /proc/acpi/ directories that have moved to /sys/ +config ACPI_REV_OVERRIDE_POSSIBLE + bool "Allow supported ACPI revision to be overriden" + depends on X86 + default y + help + The platform firmware on some systems expects Linux to return "5" as + the supported ACPI revision which makes it expose system configuration + information in a special way. + + For example, based on what ACPI exports as the supported revision, + Dell XPS 13 (2015) configures its audio device to either work in HDA + mode or in I2S mode, where the former is supposed to be used on Linux + until the latter is fully supported (in the kernel as well as in user + space). + + This option enables a DMI-based quirk for the above Dell machine (so + that HDA audio is exposed by the platform firmware to the kernel) and + makes it possible to force the kernel to return "5" as the supported + ACPI revision via the "acpi_rev_override" command line switch. + config ACPI_EC_DEBUGFS tristate "EC read/write access through /sys/kernel/debug/ec" default n diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c index 1d1791935c31..278dc4be992a 100644 --- a/drivers/acpi/blacklist.c +++ b/drivers/acpi/blacklist.c @@ -162,6 +162,15 @@ static int __init dmi_disable_osi_win8(const struct dmi_system_id *d) acpi_osi_setup("!Windows 2012"); return 0; } +#ifdef CONFIG_ACPI_REV_OVERRIDE_POSSIBLE +static int __init dmi_enable_rev_override(const struct dmi_system_id *d) +{ + printk(KERN_NOTICE PREFIX "DMI detected: %s (force ACPI _REV to 5)\n", + d->ident); + acpi_rev_override_setup(NULL); + return 0; +} +#endif static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { { @@ -325,6 +334,23 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { DMI_MATCH(DMI_PRODUCT_NAME, "1015PX"), }, }, + +#ifdef CONFIG_ACPI_REV_OVERRIDE_POSSIBLE + /* + * DELL XPS 13 (2015) switches sound between HDA and I2S + * depending on the ACPI _REV callback. If userspace supports + * I2S sufficiently (or if you do not care about sound), you + * can safely disable this quirk. + */ + { + .callback = dmi_enable_rev_override, + .ident = "DELL XPS 13 (2015)", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "XPS 13 9343"), + }, + }, +#endif {} }; diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index ba4a61e964be..42f304288829 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -58,6 +58,7 @@ void acpi_cmos_rtc_init(void); #else static inline void acpi_cmos_rtc_init(void) {} #endif +int acpi_rev_override_setup(char *str); extern bool acpi_force_hot_remove; diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 39748bb3a543..37e592798cd5 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -537,6 +537,19 @@ acpi_os_get_physical_address(void *virt, acpi_physical_address * phys) } #endif +#ifdef CONFIG_ACPI_REV_OVERRIDE_POSSIBLE +static bool acpi_rev_override; + +int __init acpi_rev_override_setup(char *str) +{ + acpi_rev_override = true; + return 1; +} +__setup("acpi_rev_override", acpi_rev_override_setup); +#else +#define acpi_rev_override false +#endif + #define ACPI_MAX_OVERRIDE_LEN 100 static char acpi_os_name[ACPI_MAX_OVERRIDE_LEN]; @@ -555,6 +568,11 @@ acpi_os_predefined_override(const struct acpi_predefined_names *init_val, *new_val = acpi_os_name; } + if (!memcmp(init_val->name, "_REV", 4) && acpi_rev_override) { + printk(KERN_INFO PREFIX "Overriding _REV return value to 5\n"); + *new_val = (char *)5; + } + return AE_OK; } -- cgit v1.2.3-70-g09d2 From ea7d521569a70418aa9f6309a1d1916709818b62 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 1 Jul 2015 23:24:05 +0200 Subject: Revert 'Revert "ACPICA: Permanently set _REV to the value '2'."' Revert commit ff284f37fc0e (Revert "ACPICA: Permanently set _REV to the value '2'.) as the regression introduced by commit b1ef29725865 reverted by it is now addressed via a blacklist entry. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/utglobal.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c index 5e8df9177da4..a72685c1e819 100644 --- a/drivers/acpi/acpica/utglobal.c +++ b/drivers/acpi/acpica/utglobal.c @@ -102,12 +102,19 @@ const struct acpi_predefined_names acpi_gbl_pre_defined_names[] = { {"_SB_", ACPI_TYPE_DEVICE, NULL}, {"_SI_", ACPI_TYPE_LOCAL_SCOPE, NULL}, {"_TZ_", ACPI_TYPE_DEVICE, NULL}, - {"_REV", ACPI_TYPE_INTEGER, (char *)ACPI_CA_SUPPORT_LEVEL}, + /* + * March, 2015: + * The _REV object is in the process of being deprecated, because + * other ACPI implementations permanently return 2. Thus, it + * has little or no value. Return 2 for compatibility with + * other ACPI implementations. + */ + {"_REV", ACPI_TYPE_INTEGER, ACPI_CAST_PTR(char, 2)}, {"_OS_", ACPI_TYPE_STRING, ACPI_OS_NAME}, - {"_GL_", ACPI_TYPE_MUTEX, (char *)1}, + {"_GL_", ACPI_TYPE_MUTEX, ACPI_CAST_PTR(char, 1)}, #if !defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY) - {"_OSI", ACPI_TYPE_METHOD, (char *)1}, + {"_OSI", ACPI_TYPE_METHOD, ACPI_CAST_PTR(char, 1)}, #endif /* Table terminator */ -- cgit v1.2.3-70-g09d2 From f617f7310cfdca5245a10629979d85682323f1a4 Mon Sep 17 00:00:00 2001 From: Roger Lucas Date: Tue, 12 May 2015 22:01:37 +0100 Subject: hwmon: (w83792d) Additional PWM outputs support Add pwm[4-7] and the associated pwm[4-7]_mode attributes. Signed-off-by: Roger Lucas Signed-off-by: Jean Delvare --- Documentation/hwmon/w83792d | 18 +++++++++++++----- drivers/hwmon/w83792d.c | 27 ++++++++++++++++++++++----- 2 files changed, 35 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/Documentation/hwmon/w83792d b/Documentation/hwmon/w83792d index 53f7b6866fec..f2ffc402ea45 100644 --- a/Documentation/hwmon/w83792d +++ b/Documentation/hwmon/w83792d @@ -8,6 +8,7 @@ Supported chips: Datasheet: http://www.winbond.com.tw Author: Shane Huang (Winbond) +Updated: Roger Lucas Module Parameters @@ -38,9 +39,16 @@ parameter; this will put it into a more well-behaved state first. The driver implements three temperature sensors, seven fan rotation speed sensors, nine voltage sensors, and two automatic fan regulation strategies called: Smart Fan I (Thermal Cruise mode) and Smart Fan II. -Automatic fan control mode is possible only for fan1-fan3. Fan4-fan7 can run -synchronized with selected fan (fan1-fan3). This functionality and manual PWM -control for fan4-fan7 is not yet implemented. + +The driver also implements up to seven fan control outputs: pwm1-7. Pwm1-7 +can be configured to PWM output or Analogue DC output via their associated +pwmX_mode. Outputs pwm4 through pwm7 may or may not be present depending on +how the W83792AD/D was configured by the BIOS. + +Automatic fan control mode is possible only for fan1-fan3. + +For all pwmX outputs, a value of 0 means minimum fan speed and a value of +255 means maximum fan speed. Temperatures are measured in degrees Celsius and measurement resolution is 1 degC for temp1 and 0.5 degC for temp2 and temp3. An alarm is triggered when @@ -157,14 +165,14 @@ for each fan. /sys files ---------- -pwm[1-3] - this file stores PWM duty cycle or DC value (fan speed) in range: +pwm[1-7] - this file stores PWM duty cycle or DC value (fan speed) in range: 0 (stop) to 255 (full) pwm[1-3]_enable - this file controls mode of fan/temperature control: * 0 Disabled * 1 Manual mode * 2 Smart Fan II * 3 Thermal Cruise -pwm[1-3]_mode - Select PWM of DC mode +pwm[1-7]_mode - Select PWM or DC mode * 0 DC * 1 PWM thermal_cruise[1-3] - Selects the desired temperature for cruise (degC) diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c index 4068db4d9580..0a8bce726b4b 100644 --- a/drivers/hwmon/w83792d.c +++ b/drivers/hwmon/w83792d.c @@ -289,10 +289,7 @@ struct w83792d_data { u8 temp1[3]; /* current, over, thyst */ u8 temp_add[2][6]; /* Register value */ u8 fan_div[7]; /* Register encoding, shifted right */ - u8 pwm[7]; /* - * We only consider the first 3 set of pwm, - * although 792 chip has 7 set of pwm. - */ + u8 pwm[7]; /* The 7 PWM outputs */ u8 pwmenable[3]; u32 alarms; /* realtime status register encoding,combined */ u8 chassis; /* Chassis status */ @@ -1075,6 +1072,10 @@ static DEVICE_ATTR(intrusion0_alarm, S_IRUGO | S_IWUSR, static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0); static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1); static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2); +static SENSOR_DEVICE_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3); +static SENSOR_DEVICE_ATTR(pwm5, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 4); +static SENSOR_DEVICE_ATTR(pwm6, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 5); +static SENSOR_DEVICE_ATTR(pwm7, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 6); static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwmenable, store_pwmenable, 1); static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, @@ -1087,6 +1088,14 @@ static SENSOR_DEVICE_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, show_pwm_mode, store_pwm_mode, 1); static SENSOR_DEVICE_ATTR(pwm3_mode, S_IWUSR | S_IRUGO, show_pwm_mode, store_pwm_mode, 2); +static SENSOR_DEVICE_ATTR(pwm4_mode, S_IWUSR | S_IRUGO, + show_pwm_mode, store_pwm_mode, 3); +static SENSOR_DEVICE_ATTR(pwm5_mode, S_IWUSR | S_IRUGO, + show_pwm_mode, store_pwm_mode, 4); +static SENSOR_DEVICE_ATTR(pwm6_mode, S_IWUSR | S_IRUGO, + show_pwm_mode, store_pwm_mode, 5); +static SENSOR_DEVICE_ATTR(pwm7_mode, S_IWUSR | S_IRUGO, + show_pwm_mode, store_pwm_mode, 6); static SENSOR_DEVICE_ATTR(tolerance1, S_IWUSR | S_IRUGO, show_tolerance, store_tolerance, 1); static SENSOR_DEVICE_ATTR(tolerance2, S_IWUSR | S_IRUGO, @@ -1177,30 +1186,38 @@ static SENSOR_DEVICE_ATTR(fan6_div, S_IWUSR | S_IRUGO, static SENSOR_DEVICE_ATTR(fan7_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 7); -static struct attribute *w83792d_attributes_fan[4][5] = { +static struct attribute *w83792d_attributes_fan[4][7] = { { &sensor_dev_attr_fan4_input.dev_attr.attr, &sensor_dev_attr_fan4_min.dev_attr.attr, &sensor_dev_attr_fan4_div.dev_attr.attr, &sensor_dev_attr_fan4_alarm.dev_attr.attr, + &sensor_dev_attr_pwm4.dev_attr.attr, + &sensor_dev_attr_pwm4_mode.dev_attr.attr, NULL }, { &sensor_dev_attr_fan5_input.dev_attr.attr, &sensor_dev_attr_fan5_min.dev_attr.attr, &sensor_dev_attr_fan5_div.dev_attr.attr, &sensor_dev_attr_fan5_alarm.dev_attr.attr, + &sensor_dev_attr_pwm5.dev_attr.attr, + &sensor_dev_attr_pwm5_mode.dev_attr.attr, NULL }, { &sensor_dev_attr_fan6_input.dev_attr.attr, &sensor_dev_attr_fan6_min.dev_attr.attr, &sensor_dev_attr_fan6_div.dev_attr.attr, &sensor_dev_attr_fan6_alarm.dev_attr.attr, + &sensor_dev_attr_pwm6.dev_attr.attr, + &sensor_dev_attr_pwm6_mode.dev_attr.attr, NULL }, { &sensor_dev_attr_fan7_input.dev_attr.attr, &sensor_dev_attr_fan7_min.dev_attr.attr, &sensor_dev_attr_fan7_div.dev_attr.attr, &sensor_dev_attr_fan7_alarm.dev_attr.attr, + &sensor_dev_attr_pwm7.dev_attr.attr, + &sensor_dev_attr_pwm7_mode.dev_attr.attr, NULL } }; -- cgit v1.2.3-70-g09d2 From ffe3df535320acc337d69c60549d68ebfa863642 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Fri, 3 Jul 2015 14:39:06 +0200 Subject: hwmon: (w83627ehf) Use swap() in w82627ehf_swap_tempreg() Use kernel.h macro definition. Thanks to Julia Lawall for Coccinelle scripting support. Signed-off-by: Fabian Frederick Signed-off-by: Jean Delvare --- drivers/hwmon/w83627ehf.c | 26 +++++--------------------- 1 file changed, 5 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index b10353b31806..697007afb99c 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -1937,27 +1937,11 @@ static inline void w83627ehf_init_device(struct w83627ehf_data *data, static void w82627ehf_swap_tempreg(struct w83627ehf_data *data, int r1, int r2) { - u16 tmp; - - tmp = data->temp_src[r1]; - data->temp_src[r1] = data->temp_src[r2]; - data->temp_src[r2] = tmp; - - tmp = data->reg_temp[r1]; - data->reg_temp[r1] = data->reg_temp[r2]; - data->reg_temp[r2] = tmp; - - tmp = data->reg_temp_over[r1]; - data->reg_temp_over[r1] = data->reg_temp_over[r2]; - data->reg_temp_over[r2] = tmp; - - tmp = data->reg_temp_hyst[r1]; - data->reg_temp_hyst[r1] = data->reg_temp_hyst[r2]; - data->reg_temp_hyst[r2] = tmp; - - tmp = data->reg_temp_config[r1]; - data->reg_temp_config[r1] = data->reg_temp_config[r2]; - data->reg_temp_config[r2] = tmp; + swap(data->temp_src[r1], data->temp_src[r2]); + swap(data->reg_temp[r1], data->reg_temp[r2]); + swap(data->reg_temp_over[r1], data->reg_temp_over[r2]); + swap(data->reg_temp_hyst[r1], data->reg_temp_hyst[r2]); + swap(data->reg_temp_config[r1], data->reg_temp_config[r2]); } static void -- cgit v1.2.3-70-g09d2 From 431dae778aea4eed31bd12e5ee82edc571cd4d70 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Mon, 29 Jun 2015 16:44:01 +0200 Subject: KVM: s390: virtio-ccw: don't overwrite config space values Eric noticed problems with vhost-scsi and virtio-ccw: vhost-scsi complained about overwriting values in the config space, which was triggered by a broken implementation of virtio-ccw's config get/set routines. It was probably sheer luck that we did not hit this before. When writing a value to the config space, the WRITE_CONF ccw will always write from the beginning of the config space up to and including the value to be set. If the config space up to the value has not yet been retrieved from the device, however, we'll end up overwriting values. Keep track of the known config space and update if needed to avoid this. Moreover, READ_CONF will only read the number of bytes it has been instructed to retrieve, so we must not copy more than that to the buffer, or we might overwrite trailing values. Reported-by: Eric Farman Signed-off-by: Cornelia Huck Reviewed-by: Eric Farman Tested-by: Eric Farman Signed-off-by: Christian Borntraeger Cc: stable@vger.kernel.org Signed-off-by: Paolo Bonzini --- drivers/s390/kvm/virtio_ccw.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/kvm/virtio_ccw.c b/drivers/s390/kvm/virtio_ccw.c index 6f1fa1773e76..f8d8fdb26b72 100644 --- a/drivers/s390/kvm/virtio_ccw.c +++ b/drivers/s390/kvm/virtio_ccw.c @@ -65,6 +65,7 @@ struct virtio_ccw_device { bool is_thinint; bool going_away; bool device_lost; + unsigned int config_ready; void *airq_info; }; @@ -833,8 +834,11 @@ static void virtio_ccw_get_config(struct virtio_device *vdev, if (ret) goto out_free; - memcpy(vcdev->config, config_area, sizeof(vcdev->config)); - memcpy(buf, &vcdev->config[offset], len); + memcpy(vcdev->config, config_area, offset + len); + if (buf) + memcpy(buf, &vcdev->config[offset], len); + if (vcdev->config_ready < offset + len) + vcdev->config_ready = offset + len; out_free: kfree(config_area); @@ -857,6 +861,9 @@ static void virtio_ccw_set_config(struct virtio_device *vdev, if (!config_area) goto out_free; + /* Make sure we don't overwrite fields. */ + if (vcdev->config_ready < offset) + virtio_ccw_get_config(vdev, 0, NULL, offset); memcpy(&vcdev->config[offset], buf, len); /* Write the config area to the host. */ memcpy(config_area, vcdev->config, sizeof(vcdev->config)); -- cgit v1.2.3-70-g09d2 From 5a8011cb896ed9822ca9086cf9c4d4c5db16be64 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 3 Jul 2015 13:49:37 +1000 Subject: crypto: marvell/cesa - another fix up for of_get_named_gen_pool() rename Signed-off-by: Stephen Rothwell Signed-off-by: Linus Torvalds --- drivers/crypto/mv_cesa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/mv_cesa.c b/drivers/crypto/mv_cesa.c index 5bcd575fa96f..e6b658faef63 100644 --- a/drivers/crypto/mv_cesa.c +++ b/drivers/crypto/mv_cesa.c @@ -1034,8 +1034,8 @@ static int mv_cesa_get_sram(struct platform_device *pdev, &sram_size); cp->sram_size = sram_size; - cp->sram_pool = of_get_named_gen_pool(pdev->dev.of_node, - "marvell,crypto-srams", 0); + cp->sram_pool = of_gen_pool_get(pdev->dev.of_node, + "marvell,crypto-srams", 0); if (cp->sram_pool) { cp->sram = gen_pool_dma_alloc(cp->sram_pool, sram_size, &cp->sram_dma); -- cgit v1.2.3-70-g09d2 From e24ff467e12e1560de753313976c46e84fa6306a Mon Sep 17 00:00:00 2001 From: Shixin Zeng Date: Fri, 3 Jul 2015 08:46:50 +0200 Subject: drm/crtc: Fix edid length computation The length of each EDID block is EDID_LENGTH, and number of blocks is (1 + edid->extensions) - we need to multiply not add them. This causes wrong EDID to be passed on, and is a regression introduced by d2ed34362a52 (drm: Introduce helper for replacing blob properties) Signed-off-by: Shixin Zeng Cc: Daniel Stone Cc: Maarten Lankhorst Reviewed-by: Daniel Stone [danvet: Add Cc: and fix commit summary.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index b69ed97d447c..b9ba06176eb1 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -4732,7 +4732,7 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector, return 0; if (edid) - size = EDID_LENGTH + (1 + edid->extensions); + size = EDID_LENGTH * (1 + edid->extensions); ret = drm_property_replace_global_blob(dev, &connector->edid_blob_ptr, -- cgit v1.2.3-70-g09d2 From a1bd3baeb2f18b2b3d0f98ce5fdaa725149b950b Mon Sep 17 00:00:00 2001 From: Allen Hubbe Date: Thu, 9 Apr 2015 10:33:20 -0400 Subject: NTB: Add NTB hardware abstraction layer Abstract the NTB device behind a programming interface, so that it can support different hardware and client drivers. Signed-off-by: Allen Hubbe Signed-off-by: Jon Mason --- Documentation/ntb.txt | 32 ++ MAINTAINERS | 4 +- drivers/ntb/Makefile | 1 + drivers/ntb/ntb.c | 251 +++++++++++++ include/linux/ntb.h | 984 ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 1271 insertions(+), 1 deletion(-) create mode 100644 Documentation/ntb.txt create mode 100644 drivers/ntb/ntb.c create mode 100644 include/linux/ntb.h (limited to 'drivers') diff --git a/Documentation/ntb.txt b/Documentation/ntb.txt new file mode 100644 index 000000000000..9d46dc9712a8 --- /dev/null +++ b/Documentation/ntb.txt @@ -0,0 +1,32 @@ +# NTB Drivers + +NTB (Non-Transparent Bridge) is a type of PCI-Express bridge chip that connects +the separate memory systems of two computers to the same PCI-Express fabric. +Existing NTB hardware supports a common feature set, including scratchpad +registers, doorbell registers, and memory translation windows. Scratchpad +registers are read-and-writable registers that are accessible from either side +of the device, so that peers can exchange a small amount of information at a +fixed address. Doorbell registers provide a way for peers to send interrupt +events. Memory windows allow translated read and write access to the peer +memory. + +## NTB Core Driver (ntb) + +The NTB core driver defines an api wrapping the common feature set, and allows +clients interested in NTB features to discover NTB the devices supported by +hardware drivers. The term "client" is used here to mean an upper layer +component making use of the NTB api. The term "driver," or "hardware driver," +is used here to mean a driver for a specific vendor and model of NTB hardware. + +## NTB Client Drivers + +NTB client drivers should register with the NTB core driver. After +registering, the client probe and remove functions will be called appropriately +as ntb hardware, or hardware drivers, are inserted and removed. The +registration uses the Linux Device framework, so it should feel familiar to +anyone who has written a pci driver. + +## NTB Hardware Drivers + +NTB hardware drivers should register devices with the NTB core driver. After +registering, clients probe and remove functions will be called. diff --git a/MAINTAINERS b/MAINTAINERS index 663bc8ed1860..e2fc9eec2e16 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6995,15 +6995,17 @@ F: drivers/power/bq27x00_battery.c F: drivers/power/isp1704_charger.c F: drivers/power/rx51_battery.c -NTB DRIVER +NTB DRIVER CORE M: Jon Mason M: Dave Jiang +M: Allen Hubbe S: Supported W: https://github.com/jonmason/ntb/wiki T: git git://github.com/jonmason/ntb.git F: drivers/ntb/ F: drivers/net/ntb_netdev.c F: include/linux/ntb.h +F: include/linux/ntb_transport.h NTFS FILESYSTEM M: Anton Altaparmakov diff --git a/drivers/ntb/Makefile b/drivers/ntb/Makefile index 545b10a131af..712e953a8fda 100644 --- a/drivers/ntb/Makefile +++ b/drivers/ntb/Makefile @@ -1,3 +1,4 @@ +obj-$(CONFIG_NTB) += ntb.o obj-$(CONFIG_NTB) += ntb_hw_intel.o ntb_hw_intel-objs := hw/intel/ntb_hw_intel.o ntb_transport.o diff --git a/drivers/ntb/ntb.c b/drivers/ntb/ntb.c new file mode 100644 index 000000000000..23435f2a5486 --- /dev/null +++ b/drivers/ntb/ntb.c @@ -0,0 +1,251 @@ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright (C) 2015 EMC Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright (C) 2015 EMC Corporation. 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 copy + * 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. + * + * PCIe NTB Linux driver + * + * Contact Information: + * Allen Hubbe + */ + +#include +#include +#include + +#include +#include + +#define DRIVER_NAME "ntb" +#define DRIVER_DESCRIPTION "PCIe NTB Driver Framework" + +#define DRIVER_LICENSE "Dual BSD/GPL" +#define DRIVER_VERSION "1.0" +#define DRIVER_RELDATE "24 March 2015" +#define DRIVER_AUTHOR "Allen Hubbe " + +MODULE_LICENSE(DRIVER_LICENSE); +MODULE_VERSION(DRIVER_VERSION); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESCRIPTION); + +static struct bus_type ntb_bus; +static void ntb_dev_release(struct device *dev); + +int __ntb_register_client(struct ntb_client *client, struct module *mod, + const char *mod_name) +{ + if (!client) + return -EINVAL; + if (!ntb_client_ops_is_valid(&client->ops)) + return -EINVAL; + + memset(&client->drv, 0, sizeof(client->drv)); + client->drv.bus = &ntb_bus; + client->drv.name = mod_name; + client->drv.owner = mod; + + return driver_register(&client->drv); +} +EXPORT_SYMBOL(__ntb_register_client); + +void ntb_unregister_client(struct ntb_client *client) +{ + driver_unregister(&client->drv); +} +EXPORT_SYMBOL(ntb_unregister_client); + +int ntb_register_device(struct ntb_dev *ntb) +{ + if (!ntb) + return -EINVAL; + if (!ntb->pdev) + return -EINVAL; + if (!ntb->ops) + return -EINVAL; + if (!ntb_dev_ops_is_valid(ntb->ops)) + return -EINVAL; + + init_completion(&ntb->released); + + memset(&ntb->dev, 0, sizeof(ntb->dev)); + ntb->dev.bus = &ntb_bus; + ntb->dev.parent = &ntb->pdev->dev; + ntb->dev.release = ntb_dev_release; + dev_set_name(&ntb->dev, pci_name(ntb->pdev)); + + ntb->ctx = NULL; + ntb->ctx_ops = NULL; + spin_lock_init(&ntb->ctx_lock); + + return device_register(&ntb->dev); +} +EXPORT_SYMBOL(ntb_register_device); + +void ntb_unregister_device(struct ntb_dev *ntb) +{ + device_unregister(&ntb->dev); + wait_for_completion(&ntb->released); +} +EXPORT_SYMBOL(ntb_unregister_device); + +int ntb_set_ctx(struct ntb_dev *ntb, void *ctx, + const struct ntb_ctx_ops *ctx_ops) +{ + unsigned long irqflags; + + if (!ntb_ctx_ops_is_valid(ctx_ops)) + return -EINVAL; + if (ntb->ctx_ops) + return -EINVAL; + + spin_lock_irqsave(&ntb->ctx_lock, irqflags); + { + ntb->ctx = ctx; + ntb->ctx_ops = ctx_ops; + } + spin_unlock_irqrestore(&ntb->ctx_lock, irqflags); + + return 0; +} +EXPORT_SYMBOL(ntb_set_ctx); + +void ntb_clear_ctx(struct ntb_dev *ntb) +{ + unsigned long irqflags; + + spin_lock_irqsave(&ntb->ctx_lock, irqflags); + { + ntb->ctx_ops = NULL; + ntb->ctx = NULL; + } + spin_unlock_irqrestore(&ntb->ctx_lock, irqflags); +} +EXPORT_SYMBOL(ntb_clear_ctx); + +void ntb_link_event(struct ntb_dev *ntb) +{ + unsigned long irqflags; + + spin_lock_irqsave(&ntb->ctx_lock, irqflags); + { + if (ntb->ctx_ops && ntb->ctx_ops->link_event) + ntb->ctx_ops->link_event(ntb->ctx); + } + spin_unlock_irqrestore(&ntb->ctx_lock, irqflags); +} +EXPORT_SYMBOL(ntb_link_event); + +void ntb_db_event(struct ntb_dev *ntb, int vector) +{ + unsigned long irqflags; + + spin_lock_irqsave(&ntb->ctx_lock, irqflags); + { + if (ntb->ctx_ops && ntb->ctx_ops->db_event) + ntb->ctx_ops->db_event(ntb->ctx, vector); + } + spin_unlock_irqrestore(&ntb->ctx_lock, irqflags); +} +EXPORT_SYMBOL(ntb_db_event); + +static int ntb_probe(struct device *dev) +{ + struct ntb_dev *ntb; + struct ntb_client *client; + int rc; + + get_device(dev); + ntb = dev_ntb(dev); + client = drv_ntb_client(dev->driver); + + rc = client->ops.probe(client, ntb); + if (rc) + put_device(dev); + + return rc; +} + +static int ntb_remove(struct device *dev) +{ + struct ntb_dev *ntb; + struct ntb_client *client; + + if (dev->driver) { + ntb = dev_ntb(dev); + client = drv_ntb_client(dev->driver); + + client->ops.remove(client, ntb); + put_device(dev); + } + + return 0; +} + +static void ntb_dev_release(struct device *dev) +{ + struct ntb_dev *ntb = dev_ntb(dev); + + complete(&ntb->released); +} + +static struct bus_type ntb_bus = { + .name = "ntb", + .probe = ntb_probe, + .remove = ntb_remove, +}; + +static int __init ntb_driver_init(void) +{ + return bus_register(&ntb_bus); +} +module_init(ntb_driver_init); + +static void __exit ntb_driver_exit(void) +{ + bus_unregister(&ntb_bus); +} +module_exit(ntb_driver_exit); + diff --git a/include/linux/ntb.h b/include/linux/ntb.h new file mode 100644 index 000000000000..b02f72bb8e32 --- /dev/null +++ b/include/linux/ntb.h @@ -0,0 +1,984 @@ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright (C) 2015 EMC Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright (C) 2015 EMC Corporation. 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 copy + * 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. + * + * PCIe NTB Linux driver + * + * Contact Information: + * Allen Hubbe + */ + +#ifndef _NTB_H_ +#define _NTB_H_ + +#include +#include + +struct ntb_client; +struct ntb_dev; +struct pci_dev; + +/** + * enum ntb_topo - NTB connection topology + * @NTB_TOPO_NONE: Topology is unknown or invalid. + * @NTB_TOPO_PRI: On primary side of local ntb. + * @NTB_TOPO_SEC: On secondary side of remote ntb. + * @NTB_TOPO_B2B_USD: On primary side of local ntb upstream of remote ntb. + * @NTB_TOPO_B2B_DSD: On primary side of local ntb downstream of remote ntb. + */ +enum ntb_topo { + NTB_TOPO_NONE = -1, + NTB_TOPO_PRI, + NTB_TOPO_SEC, + NTB_TOPO_B2B_USD, + NTB_TOPO_B2B_DSD, +}; + +static inline int ntb_topo_is_b2b(enum ntb_topo topo) +{ + switch ((int)topo) { + case NTB_TOPO_B2B_USD: + case NTB_TOPO_B2B_DSD: + return 1; + } + return 0; +} + +static inline char *ntb_topo_string(enum ntb_topo topo) +{ + switch (topo) { + case NTB_TOPO_NONE: return "NTB_TOPO_NONE"; + case NTB_TOPO_PRI: return "NTB_TOPO_PRI"; + case NTB_TOPO_SEC: return "NTB_TOPO_SEC"; + case NTB_TOPO_B2B_USD: return "NTB_TOPO_B2B_USD"; + case NTB_TOPO_B2B_DSD: return "NTB_TOPO_B2B_DSD"; + } + return "NTB_TOPO_INVALID"; +} + +/** + * enum ntb_speed - NTB link training speed + * @NTB_SPEED_AUTO: Request the max supported speed. + * @NTB_SPEED_NONE: Link is not trained to any speed. + * @NTB_SPEED_GEN1: Link is trained to gen1 speed. + * @NTB_SPEED_GEN2: Link is trained to gen2 speed. + * @NTB_SPEED_GEN3: Link is trained to gen3 speed. + */ +enum ntb_speed { + NTB_SPEED_AUTO = -1, + NTB_SPEED_NONE = 0, + NTB_SPEED_GEN1 = 1, + NTB_SPEED_GEN2 = 2, + NTB_SPEED_GEN3 = 3, +}; + +/** + * enum ntb_width - NTB link training width + * @NTB_WIDTH_AUTO: Request the max supported width. + * @NTB_WIDTH_NONE: Link is not trained to any width. + * @NTB_WIDTH_1: Link is trained to 1 lane width. + * @NTB_WIDTH_2: Link is trained to 2 lane width. + * @NTB_WIDTH_4: Link is trained to 4 lane width. + * @NTB_WIDTH_8: Link is trained to 8 lane width. + * @NTB_WIDTH_12: Link is trained to 12 lane width. + * @NTB_WIDTH_16: Link is trained to 16 lane width. + * @NTB_WIDTH_32: Link is trained to 32 lane width. + */ +enum ntb_width { + NTB_WIDTH_AUTO = -1, + NTB_WIDTH_NONE = 0, + NTB_WIDTH_1 = 1, + NTB_WIDTH_2 = 2, + NTB_WIDTH_4 = 4, + NTB_WIDTH_8 = 8, + NTB_WIDTH_12 = 12, + NTB_WIDTH_16 = 16, + NTB_WIDTH_32 = 32, +}; + +/** + * struct ntb_client_ops - ntb client operations + * @probe: Notify client of a new device. + * @remove: Notify client to remove a device. + */ +struct ntb_client_ops { + int (*probe)(struct ntb_client *client, struct ntb_dev *ntb); + void (*remove)(struct ntb_client *client, struct ntb_dev *ntb); +}; + +static inline int ntb_client_ops_is_valid(const struct ntb_client_ops *ops) +{ + /* commented callbacks are not required: */ + return + ops->probe && + ops->remove && + 1; +} + +/** + * struct ntb_ctx_ops - ntb driver context operations + * @link_event: See ntb_link_event(). + * @db_event: See ntb_db_event(). + */ +struct ntb_ctx_ops { + void (*link_event)(void *ctx); + void (*db_event)(void *ctx, int db_vector); +}; + +static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops) +{ + /* commented callbacks are not required: */ + return + /* ops->link_event && */ + /* ops->db_event && */ + 1; +} + +/** + * struct ntb_ctx_ops - ntb device operations + * @mw_count: See ntb_mw_count(). + * @mw_get_range: See ntb_mw_get_range(). + * @mw_set_trans: See ntb_mw_set_trans(). + * @mw_clear_trans: See ntb_mw_clear_trans(). + * @link_is_up: See ntb_link_is_up(). + * @link_enable: See ntb_link_enable(). + * @link_disable: See ntb_link_disable(). + * @db_is_unsafe: See ntb_db_is_unsafe(). + * @db_valid_mask: See ntb_db_valid_mask(). + * @db_vector_count: See ntb_db_vector_count(). + * @db_vector_mask: See ntb_db_vector_mask(). + * @db_read: See ntb_db_read(). + * @db_set: See ntb_db_set(). + * @db_clear: See ntb_db_clear(). + * @db_read_mask: See ntb_db_read_mask(). + * @db_set_mask: See ntb_db_set_mask(). + * @db_clear_mask: See ntb_db_clear_mask(). + * @peer_db_addr: See ntb_peer_db_addr(). + * @peer_db_read: See ntb_peer_db_read(). + * @peer_db_set: See ntb_peer_db_set(). + * @peer_db_clear: See ntb_peer_db_clear(). + * @peer_db_read_mask: See ntb_peer_db_read_mask(). + * @peer_db_set_mask: See ntb_peer_db_set_mask(). + * @peer_db_clear_mask: See ntb_peer_db_clear_mask(). + * @spad_is_unsafe: See ntb_spad_is_unsafe(). + * @spad_count: See ntb_spad_count(). + * @spad_read: See ntb_spad_read(). + * @spad_write: See ntb_spad_write(). + * @peer_spad_addr: See ntb_peer_spad_addr(). + * @peer_spad_read: See ntb_peer_spad_read(). + * @peer_spad_write: See ntb_peer_spad_write(). + */ +struct ntb_dev_ops { + int (*mw_count)(struct ntb_dev *ntb); + int (*mw_get_range)(struct ntb_dev *ntb, int idx, + phys_addr_t *base, resource_size_t *size, + resource_size_t *align, resource_size_t *align_size); + int (*mw_set_trans)(struct ntb_dev *ntb, int idx, + dma_addr_t addr, resource_size_t size); + int (*mw_clear_trans)(struct ntb_dev *ntb, int idx); + + int (*link_is_up)(struct ntb_dev *ntb, + enum ntb_speed *speed, enum ntb_width *width); + int (*link_enable)(struct ntb_dev *ntb, + enum ntb_speed max_speed, enum ntb_width max_width); + int (*link_disable)(struct ntb_dev *ntb); + + int (*db_is_unsafe)(struct ntb_dev *ntb); + u64 (*db_valid_mask)(struct ntb_dev *ntb); + int (*db_vector_count)(struct ntb_dev *ntb); + u64 (*db_vector_mask)(struct ntb_dev *ntb, int db_vector); + + u64 (*db_read)(struct ntb_dev *ntb); + int (*db_set)(struct ntb_dev *ntb, u64 db_bits); + int (*db_clear)(struct ntb_dev *ntb, u64 db_bits); + + u64 (*db_read_mask)(struct ntb_dev *ntb); + int (*db_set_mask)(struct ntb_dev *ntb, u64 db_bits); + int (*db_clear_mask)(struct ntb_dev *ntb, u64 db_bits); + + int (*peer_db_addr)(struct ntb_dev *ntb, + phys_addr_t *db_addr, resource_size_t *db_size); + u64 (*peer_db_read)(struct ntb_dev *ntb); + int (*peer_db_set)(struct ntb_dev *ntb, u64 db_bits); + int (*peer_db_clear)(struct ntb_dev *ntb, u64 db_bits); + + u64 (*peer_db_read_mask)(struct ntb_dev *ntb); + int (*peer_db_set_mask)(struct ntb_dev *ntb, u64 db_bits); + int (*peer_db_clear_mask)(struct ntb_dev *ntb, u64 db_bits); + + int (*spad_is_unsafe)(struct ntb_dev *ntb); + int (*spad_count)(struct ntb_dev *ntb); + + u32 (*spad_read)(struct ntb_dev *ntb, int idx); + int (*spad_write)(struct ntb_dev *ntb, int idx, u32 val); + + int (*peer_spad_addr)(struct ntb_dev *ntb, int idx, + phys_addr_t *spad_addr); + u32 (*peer_spad_read)(struct ntb_dev *ntb, int idx); + int (*peer_spad_write)(struct ntb_dev *ntb, int idx, u32 val); +}; + +static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops) +{ + /* commented callbacks are not required: */ + return + ops->mw_count && + ops->mw_get_range && + ops->mw_set_trans && + /* ops->mw_clear_trans && */ + ops->link_is_up && + ops->link_enable && + ops->link_disable && + /* ops->db_is_unsafe && */ + ops->db_valid_mask && + + /* both set, or both unset */ + (!ops->db_vector_count == !ops->db_vector_mask) && + + ops->db_read && + /* ops->db_set && */ + ops->db_clear && + /* ops->db_read_mask && */ + ops->db_set_mask && + ops->db_clear_mask && + ops->peer_db_addr && + /* ops->peer_db_read && */ + ops->peer_db_set && + /* ops->peer_db_clear && */ + /* ops->peer_db_read_mask && */ + /* ops->peer_db_set_mask && */ + /* ops->peer_db_clear_mask && */ + /* ops->spad_is_unsafe && */ + ops->spad_count && + ops->spad_read && + ops->spad_write && + ops->peer_spad_addr && + /* ops->peer_spad_read && */ + ops->peer_spad_write && + 1; +} + +/** + * struct ntb_client - client interested in ntb devices + * @drv: Linux driver object. + * @ops: See &ntb_client_ops. + */ +struct ntb_client { + struct device_driver drv; + const struct ntb_client_ops ops; +}; + +#define drv_ntb_client(__drv) container_of((__drv), struct ntb_client, drv) + +/** + * struct ntb_device - ntb device + * @dev: Linux device object. + * @pdev: Pci device entry of the ntb. + * @topo: Detected topology of the ntb. + * @ops: See &ntb_dev_ops. + * @ctx: See &ntb_ctx_ops. + * @ctx_ops: See &ntb_ctx_ops. + */ +struct ntb_dev { + struct device dev; + struct pci_dev *pdev; + enum ntb_topo topo; + const struct ntb_dev_ops *ops; + void *ctx; + const struct ntb_ctx_ops *ctx_ops; + + /* private: */ + + /* synchronize setting, clearing, and calling ctx_ops */ + spinlock_t ctx_lock; + /* block unregister until device is fully released */ + struct completion released; +}; + +#define dev_ntb(__dev) container_of((__dev), struct ntb_dev, dev) + +/** + * ntb_register_client() - register a client for interest in ntb devices + * @client: Client context. + * + * The client will be added to the list of clients interested in ntb devices. + * The client will be notified of any ntb devices that are not already + * associated with a client, or if ntb devices are registered later. + * + * Return: Zero if the client is registered, otherwise an error number. + */ +#define ntb_register_client(client) \ + __ntb_register_client((client), THIS_MODULE, KBUILD_MODNAME) + +int __ntb_register_client(struct ntb_client *client, struct module *mod, + const char *mod_name); + +/** + * ntb_unregister_client() - unregister a client for interest in ntb devices + * @client: Client context. + * + * The client will be removed from the list of clients interested in ntb + * devices. If any ntb devices are associated with the client, the client will + * be notified to remove those devices. + */ +void ntb_unregister_client(struct ntb_client *client); + +#define module_ntb_client(__ntb_client) \ + module_driver(__ntb_client, ntb_register_client, \ + ntb_unregister_client) + +/** + * ntb_register_device() - register a ntb device + * @ntb: NTB device context. + * + * The device will be added to the list of ntb devices. If any clients are + * interested in ntb devices, each client will be notified of the ntb device, + * until at most one client accepts the device. + * + * Return: Zero if the device is registered, otherwise an error number. + */ +int ntb_register_device(struct ntb_dev *ntb); + +/** + * ntb_register_device() - unregister a ntb device + * @ntb: NTB device context. + * + * The device will be removed from the list of ntb devices. If the ntb device + * is associated with a client, the client will be notified to remove the + * device. + */ +void ntb_unregister_device(struct ntb_dev *ntb); + +/** + * ntb_set_ctx() - associate a driver context with an ntb device + * @ntb: NTB device context. + * @ctx: Driver context. + * @ctx_ops: Driver context operations. + * + * Associate a driver context and operations with a ntb device. The context is + * provided by the client driver, and the driver may associate a different + * context with each ntb device. + * + * Return: Zero if the context is associated, otherwise an error number. + */ +int ntb_set_ctx(struct ntb_dev *ntb, void *ctx, + const struct ntb_ctx_ops *ctx_ops); + +/** + * ntb_clear_ctx() - disassociate any driver context from an ntb device + * @ntb: NTB device context. + * + * Clear any association that may exist between a driver context and the ntb + * device. + */ +void ntb_clear_ctx(struct ntb_dev *ntb); + +/** + * ntb_link_event() - notify driver context of a change in link status + * @ntb: NTB device context. + * + * Notify the driver context that the link status may have changed. The driver + * should call ntb_link_is_up() to get the current status. + */ +void ntb_link_event(struct ntb_dev *ntb); + +/** + * ntb_db_event() - notify driver context of a doorbell event + * @ntb: NTB device context. + * @vector: Interrupt vector number. + * + * Notify the driver context of a doorbell event. If hardware supports + * multiple interrupt vectors for doorbells, the vector number indicates which + * vector received the interrupt. The vector number is relative to the first + * vector used for doorbells, starting at zero, and must be less than + ** ntb_db_vector_count(). The driver may call ntb_db_read() to check which + * doorbell bits need service, and ntb_db_vector_mask() to determine which of + * those bits are associated with the vector number. + */ +void ntb_db_event(struct ntb_dev *ntb, int vector); + +/** + * ntb_mw_count() - get the number of memory windows + * @ntb: NTB device context. + * + * Hardware and topology may support a different number of memory windows. + * + * Return: the number of memory windows. + */ +static inline int ntb_mw_count(struct ntb_dev *ntb) +{ + return ntb->ops->mw_count(ntb); +} + +/** + * ntb_mw_get_range() - get the range of a memory window + * @ntb: NTB device context. + * @idx: Memory window number. + * @base: OUT - the base address for mapping the memory window + * @size: OUT - the size for mapping the memory window + * @align: OUT - the base alignment for translating the memory window + * @align_size: OUT - the size alignment for translating the memory window + * + * Get the range of a memory window. NULL may be given for any output + * parameter if the value is not needed. The base and size may be used for + * mapping the memory window, to access the peer memory. The alignment and + * size may be used for translating the memory window, for the peer to access + * memory on the local system. + * + * Return: Zero on success, otherwise an error number. + */ +static inline int ntb_mw_get_range(struct ntb_dev *ntb, int idx, + phys_addr_t *base, resource_size_t *size, + resource_size_t *align, resource_size_t *align_size) +{ + return ntb->ops->mw_get_range(ntb, idx, base, size, + align, align_size); +} + +/** + * ntb_mw_set_trans() - set the translation of a memory window + * @ntb: NTB device context. + * @idx: Memory window number. + * @addr: The dma address local memory to expose to the peer. + * @size: The size of the local memory to expose to the peer. + * + * Set the translation of a memory window. The peer may access local memory + * through the window starting at the address, up to the size. The address + * must be aligned to the alignment specified by ntb_mw_get_range(). The size + * must be aligned to the size alignment specified by ntb_mw_get_range(). + * + * Return: Zero on success, otherwise an error number. + */ +static inline int ntb_mw_set_trans(struct ntb_dev *ntb, int idx, + dma_addr_t addr, resource_size_t size) +{ + return ntb->ops->mw_set_trans(ntb, idx, addr, size); +} + +/** + * ntb_mw_clear_trans() - clear the translation of a memory window + * @ntb: NTB device context. + * @idx: Memory window number. + * + * Clear the translation of a memory window. The peer may no longer access + * local memory through the window. + * + * Return: Zero on success, otherwise an error number. + */ +static inline int ntb_mw_clear_trans(struct ntb_dev *ntb, int idx) +{ + if (!ntb->ops->mw_clear_trans) + return ntb->ops->mw_set_trans(ntb, idx, 0, 0); + + return ntb->ops->mw_clear_trans(ntb, idx); +} + +/** + * ntb_link_is_up() - get the current ntb link state + * @ntb: NTB device context. + * @speed: OUT - The link speed expressed as PCIe generation number. + * @width: OUT - The link width expressed as the number of PCIe lanes. + * + * Set the translation of a memory window. The peer may access local memory + * through the window starting at the address, up to the size. The address + * must be aligned to the alignment specified by ntb_mw_get_range(). The size + * must be aligned to the size alignment specified by ntb_mw_get_range(). + * + * Return: One if the link is up, zero if the link is down, otherwise a + * negative value indicating the error number. + */ +static inline int ntb_link_is_up(struct ntb_dev *ntb, + enum ntb_speed *speed, enum ntb_width *width) +{ + return ntb->ops->link_is_up(ntb, speed, width); +} + +/** + * ntb_link_enable() - enable the link on the secondary side of the ntb + * @ntb: NTB device context. + * @max_speed: The maximum link speed expressed as PCIe generation number. + * @max_width: The maximum link width expressed as the number of PCIe lanes. + * + * Enable the link on the secondary side of the ntb. This can only be done + * from the primary side of the ntb in primary or b2b topology. The ntb device + * should train the link to its maximum speed and width, or the requested speed + * and width, whichever is smaller, if supported. + * + * Return: Zero on success, otherwise an error number. + */ +static inline int ntb_link_enable(struct ntb_dev *ntb, + enum ntb_speed max_speed, + enum ntb_width max_width) +{ + return ntb->ops->link_enable(ntb, max_speed, max_width); +} + +/** + * ntb_link_disable() - disable the link on the secondary side of the ntb + * @ntb: NTB device context. + * + * Disable the link on the secondary side of the ntb. This can only be + * done from the primary side of the ntb in primary or b2b topology. The ntb + * device should disable the link. Returning from this call must indicate that + * a barrier has passed, though with no more writes may pass in either + * direction across the link, except if this call returns an error number. + * + * Return: Zero on success, otherwise an error number. + */ +static inline int ntb_link_disable(struct ntb_dev *ntb) +{ + return ntb->ops->link_disable(ntb); +} + +/** + * ntb_db_is_unsafe() - check if it is safe to use hardware doorbell + * @ntb: NTB device context. + * + * It is possible for some ntb hardware to be affected by errata. Hardware + * drivers can advise clients to avoid using doorbells. Clients may ignore + * this advice, though caution is recommended. + * + * Return: Zero if it is safe to use doorbells, or One if it is not safe. + */ +static inline int ntb_db_is_unsafe(struct ntb_dev *ntb) +{ + if (!ntb->ops->db_is_unsafe) + return 0; + + return ntb->ops->db_is_unsafe(ntb); +} + +/** + * ntb_db_valid_mask() - get a mask of doorbell bits supported by the ntb + * @ntb: NTB device context. + * + * Hardware may support different number or arrangement of doorbell bits. + * + * Return: A mask of doorbell bits supported by the ntb. + */ +static inline u64 ntb_db_valid_mask(struct ntb_dev *ntb) +{ + return ntb->ops->db_valid_mask(ntb); +} + +/** + * ntb_db_vector_count() - get the number of doorbell interrupt vectors + * @ntb: NTB device context. + * + * Hardware may support different number of interrupt vectors. + * + * Return: The number of doorbell interrupt vectors. + */ +static inline int ntb_db_vector_count(struct ntb_dev *ntb) +{ + if (!ntb->ops->db_vector_count) + return 1; + + return ntb->ops->db_vector_count(ntb); +} + +/** + * ntb_db_vector_mask() - get a mask of doorbell bits serviced by a vector + * @ntb: NTB device context. + * @vector: Doorbell vector number. + * + * Each interrupt vector may have a different number or arrangement of bits. + * + * Return: A mask of doorbell bits serviced by a vector. + */ +static inline u64 ntb_db_vector_mask(struct ntb_dev *ntb, int vector) +{ + if (!ntb->ops->db_vector_mask) + return ntb_db_valid_mask(ntb); + + return ntb->ops->db_vector_mask(ntb, vector); +} + +/** + * ntb_db_read() - read the local doorbell register + * @ntb: NTB device context. + * + * Read the local doorbell register, and return the bits that are set. + * + * Return: The bits currently set in the local doorbell register. + */ +static inline u64 ntb_db_read(struct ntb_dev *ntb) +{ + return ntb->ops->db_read(ntb); +} + +/** + * ntb_db_set() - set bits in the local doorbell register + * @ntb: NTB device context. + * @db_bits: Doorbell bits to set. + * + * Set bits in the local doorbell register, which may generate a local doorbell + * interrupt. Bits that were already set must remain set. + * + * This is unusual, and hardware may not support it. + * + * Return: Zero on success, otherwise an error number. + */ +static inline int ntb_db_set(struct ntb_dev *ntb, u64 db_bits) +{ + if (!ntb->ops->db_set) + return -EINVAL; + + return ntb->ops->db_set(ntb, db_bits); +} + +/** + * ntb_db_clear() - clear bits in the local doorbell register + * @ntb: NTB device context. + * @db_bits: Doorbell bits to clear. + * + * Clear bits in the local doorbell register, arming the bits for the next + * doorbell. + * + * Return: Zero on success, otherwise an error number. + */ +static inline int ntb_db_clear(struct ntb_dev *ntb, u64 db_bits) +{ + return ntb->ops->db_clear(ntb, db_bits); +} + +/** + * ntb_db_read_mask() - read the local doorbell mask + * @ntb: NTB device context. + * + * Read the local doorbell mask register, and return the bits that are set. + * + * This is unusual, though hardware is likely to support it. + * + * Return: The bits currently set in the local doorbell mask register. + */ +static inline u64 ntb_db_read_mask(struct ntb_dev *ntb) +{ + if (!ntb->ops->db_read_mask) + return 0; + + return ntb->ops->db_read_mask(ntb); +} + +/** + * ntb_db_set_mask() - set bits in the local doorbell mask + * @ntb: NTB device context. + * @db_bits: Doorbell mask bits to set. + * + * Set bits in the local doorbell mask register, preventing doorbell interrupts + * from being generated for those doorbell bits. Bits that were already set + * must remain set. + * + * Return: Zero on success, otherwise an error number. + */ +static inline int ntb_db_set_mask(struct ntb_dev *ntb, u64 db_bits) +{ + return ntb->ops->db_set_mask(ntb, db_bits); +} + +/** + * ntb_db_clear_mask() - clear bits in the local doorbell mask + * @ntb: NTB device context. + * @db_bits: Doorbell bits to clear. + * + * Clear bits in the local doorbell mask register, allowing doorbell interrupts + * from being generated for those doorbell bits. If a doorbell bit is already + * set at the time the mask is cleared, and the corresponding mask bit is + * changed from set to clear, then the ntb driver must ensure that + * ntb_db_event() is called. If the hardware does not generate the interrupt + * on clearing the mask bit, then the driver must call ntb_db_event() anyway. + * + * Return: Zero on success, otherwise an error number. + */ +static inline int ntb_db_clear_mask(struct ntb_dev *ntb, u64 db_bits) +{ + return ntb->ops->db_clear_mask(ntb, db_bits); +} + +/** + * ntb_peer_db_addr() - address and size of the peer doorbell register + * @ntb: NTB device context. + * @db_addr: OUT - The address of the peer doorbell register. + * @db_size: OUT - The number of bytes to write the peer doorbell register. + * + * Return the address of the peer doorbell register. This may be used, for + * example, by drivers that offload memory copy operations to a dma engine. + * The drivers may wish to ring the peer doorbell at the completion of memory + * copy operations. For efficiency, and to simplify ordering of operations + * between the dma memory copies and the ringing doorbell, the driver may + * append one additional dma memory copy with the doorbell register as the + * destination, after the memory copy operations. + * + * Return: Zero on success, otherwise an error number. + */ +static inline int ntb_peer_db_addr(struct ntb_dev *ntb, + phys_addr_t *db_addr, + resource_size_t *db_size) +{ + return ntb->ops->peer_db_addr(ntb, db_addr, db_size); +} + +/** + * ntb_peer_db_read() - read the peer doorbell register + * @ntb: NTB device context. + * + * Read the peer doorbell register, and return the bits that are set. + * + * This is unusual, and hardware may not support it. + * + * Return: The bits currently set in the peer doorbell register. + */ +static inline u64 ntb_peer_db_read(struct ntb_dev *ntb) +{ + if (!ntb->ops->peer_db_read) + return 0; + + return ntb->ops->peer_db_read(ntb); +} + +/** + * ntb_peer_db_set() - set bits in the peer doorbell register + * @ntb: NTB device context. + * @db_bits: Doorbell bits to set. + * + * Set bits in the peer doorbell register, which may generate a peer doorbell + * interrupt. Bits that were already set must remain set. + * + * Return: Zero on success, otherwise an error number. + */ +static inline int ntb_peer_db_set(struct ntb_dev *ntb, u64 db_bits) +{ + return ntb->ops->peer_db_set(ntb, db_bits); +} + +/** + * ntb_peer_db_clear() - clear bits in the local doorbell register + * @ntb: NTB device context. + * @db_bits: Doorbell bits to clear. + * + * Clear bits in the peer doorbell register, arming the bits for the next + * doorbell. + * + * This is unusual, and hardware may not support it. + * + * Return: Zero on success, otherwise an error number. + */ +static inline int ntb_peer_db_clear(struct ntb_dev *ntb, u64 db_bits) +{ + if (!ntb->ops->db_clear) + return -EINVAL; + + return ntb->ops->peer_db_clear(ntb, db_bits); +} + +/** + * ntb_peer_db_read_mask() - read the peer doorbell mask + * @ntb: NTB device context. + * + * Read the peer doorbell mask register, and return the bits that are set. + * + * This is unusual, and hardware may not support it. + * + * Return: The bits currently set in the peer doorbell mask register. + */ +static inline u64 ntb_peer_db_read_mask(struct ntb_dev *ntb) +{ + if (!ntb->ops->db_read_mask) + return 0; + + return ntb->ops->peer_db_read_mask(ntb); +} + +/** + * ntb_peer_db_set_mask() - set bits in the peer doorbell mask + * @ntb: NTB device context. + * @db_bits: Doorbell mask bits to set. + * + * Set bits in the peer doorbell mask register, preventing doorbell interrupts + * from being generated for those doorbell bits. Bits that were already set + * must remain set. + * + * This is unusual, and hardware may not support it. + * + * Return: Zero on success, otherwise an error number. + */ +static inline int ntb_peer_db_set_mask(struct ntb_dev *ntb, u64 db_bits) +{ + if (!ntb->ops->db_set_mask) + return -EINVAL; + + return ntb->ops->peer_db_set_mask(ntb, db_bits); +} + +/** + * ntb_peer_db_clear_mask() - clear bits in the peer doorbell mask + * @ntb: NTB device context. + * @db_bits: Doorbell bits to clear. + * + * Clear bits in the peer doorbell mask register, allowing doorbell interrupts + * from being generated for those doorbell bits. If the hardware does not + * generate the interrupt on clearing the mask bit, then the driver should not + * implement this function! + * + * This is unusual, and hardware may not support it. + * + * Return: Zero on success, otherwise an error number. + */ +static inline int ntb_peer_db_clear_mask(struct ntb_dev *ntb, u64 db_bits) +{ + if (!ntb->ops->db_clear_mask) + return -EINVAL; + + return ntb->ops->peer_db_clear_mask(ntb, db_bits); +} + +/** + * ntb_spad_is_unsafe() - check if it is safe to use the hardware scratchpads + * @ntb: NTB device context. + * + * It is possible for some ntb hardware to be affected by errata. Hardware + * drivers can advise clients to avoid using scratchpads. Clients may ignore + * this advice, though caution is recommended. + * + * Return: Zero if it is safe to use scratchpads, or One if it is not safe. + */ +static inline int ntb_spad_is_unsafe(struct ntb_dev *ntb) +{ + if (!ntb->ops->spad_is_unsafe) + return 0; + + return ntb->ops->spad_is_unsafe(ntb); +} + +/** + * ntb_mw_count() - get the number of scratchpads + * @ntb: NTB device context. + * + * Hardware and topology may support a different number of scratchpads. + * + * Return: the number of scratchpads. + */ +static inline int ntb_spad_count(struct ntb_dev *ntb) +{ + return ntb->ops->spad_count(ntb); +} + +/** + * ntb_spad_read() - read the local scratchpad register + * @ntb: NTB device context. + * @idx: Scratchpad index. + * + * Read the local scratchpad register, and return the value. + * + * Return: The value of the local scratchpad register. + */ +static inline u32 ntb_spad_read(struct ntb_dev *ntb, int idx) +{ + return ntb->ops->spad_read(ntb, idx); +} + +/** + * ntb_spad_write() - write the local scratchpad register + * @ntb: NTB device context. + * @idx: Scratchpad index. + * @val: Scratchpad value. + * + * Write the value to the local scratchpad register. + * + * Return: Zero on success, otherwise an error number. + */ +static inline int ntb_spad_write(struct ntb_dev *ntb, int idx, u32 val) +{ + return ntb->ops->spad_write(ntb, idx, val); +} + +/** + * ntb_peer_spad_addr() - address of the peer scratchpad register + * @ntb: NTB device context. + * @idx: Scratchpad index. + * @spad_addr: OUT - The address of the peer scratchpad register. + * + * Return the address of the peer doorbell register. This may be used, for + * example, by drivers that offload memory copy operations to a dma engine. + * + * Return: Zero on success, otherwise an error number. + */ +static inline int ntb_peer_spad_addr(struct ntb_dev *ntb, int idx, + phys_addr_t *spad_addr) +{ + return ntb->ops->peer_spad_addr(ntb, idx, spad_addr); +} + +/** + * ntb_peer_spad_read() - read the peer scratchpad register + * @ntb: NTB device context. + * @idx: Scratchpad index. + * + * Read the peer scratchpad register, and return the value. + * + * Return: The value of the local scratchpad register. + */ +static inline u32 ntb_peer_spad_read(struct ntb_dev *ntb, int idx) +{ + return ntb->ops->peer_spad_read(ntb, idx); +} + +/** + * ntb_peer_spad_write() - write the peer scratchpad register + * @ntb: NTB device context. + * @idx: Scratchpad index. + * @val: Scratchpad value. + * + * Write the value to the peer scratchpad register. + * + * Return: Zero on success, otherwise an error number. + */ +static inline int ntb_peer_spad_write(struct ntb_dev *ntb, int idx, u32 val) +{ + return ntb->ops->peer_spad_write(ntb, idx, val); +} + +#endif -- cgit v1.2.3-70-g09d2 From e26a5843f7f5014ae4460030ca4de029a3ac35d3 Mon Sep 17 00:00:00 2001 From: Allen Hubbe Date: Thu, 9 Apr 2015 10:33:20 -0400 Subject: NTB: Split ntb_hw_intel and ntb_transport drivers Change ntb_hw_intel to use the new NTB hardware abstraction layer. Split ntb_transport into its own driver. Change it to use the new NTB hardware abstraction layer. Signed-off-by: Allen Hubbe Signed-off-by: Jon Mason --- Documentation/ntb.txt | 26 + MAINTAINERS | 8 + drivers/net/ntb_netdev.c | 54 +- drivers/ntb/Kconfig | 37 +- drivers/ntb/Makefile | 6 +- drivers/ntb/hw/Kconfig | 1 + drivers/ntb/hw/Makefile | 1 + drivers/ntb/hw/intel/Kconfig | 7 + drivers/ntb/hw/intel/Makefile | 1 + drivers/ntb/hw/intel/ntb_hw_intel.c | 3075 +++++++++++++++++++---------------- drivers/ntb/hw/intel/ntb_hw_intel.h | 607 ++++--- drivers/ntb/ntb_transport.c | 936 ++++++----- include/linux/ntb_transport.h | 25 +- 13 files changed, 2589 insertions(+), 2195 deletions(-) create mode 100644 drivers/ntb/hw/Kconfig create mode 100644 drivers/ntb/hw/Makefile create mode 100644 drivers/ntb/hw/intel/Kconfig create mode 100644 drivers/ntb/hw/intel/Makefile (limited to 'drivers') diff --git a/Documentation/ntb.txt b/Documentation/ntb.txt index 9d46dc9712a8..725ba1e6c127 100644 --- a/Documentation/ntb.txt +++ b/Documentation/ntb.txt @@ -26,7 +26,33 @@ as ntb hardware, or hardware drivers, are inserted and removed. The registration uses the Linux Device framework, so it should feel familiar to anyone who has written a pci driver. +### NTB Transport Client (ntb\_transport) and NTB Netdev (ntb\_netdev) + +The primary client for NTB is the Transport client, used in tandem with NTB +Netdev. These drivers function together to create a logical link to the peer, +across the ntb, to exchange packets of network data. The Transport client +establishes a logical link to the peer, and creates queue pairs to exchange +messages and data. The NTB Netdev then creates an ethernet device using a +Transport queue pair. Network data is copied between socket buffers and the +Transport queue pair buffer. The Transport client may be used for other things +besides Netdev, however no other applications have yet been written. + ## NTB Hardware Drivers NTB hardware drivers should register devices with the NTB core driver. After registering, clients probe and remove functions will be called. + +### NTB Intel Hardware Driver (ntb\_hw\_intel) + +The Intel hardware driver supports NTB on Xeon and Atom CPUs. + +Module Parameters: + +* b2b\_mw\_idx - If the peer ntb is to be accessed via a memory window, then use + this memory window to access the peer ntb. A value of zero or positive + starts from the first mw idx, and a negative value starts from the last + mw idx. Both sides MUST set the same value here! The default value is + `-1`. +* b2b\_mw\_share - If the peer ntb is to be accessed via a memory window, and if + the memory window is large enough, still allow the client to use the + second half of the memory window for address translation to the peer. diff --git a/MAINTAINERS b/MAINTAINERS index e2fc9eec2e16..a682805d6d56 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7007,6 +7007,14 @@ F: drivers/net/ntb_netdev.c F: include/linux/ntb.h F: include/linux/ntb_transport.h +NTB INTEL DRIVER +M: Jon Mason +M: Dave Jiang +S: Supported +W: https://github.com/jonmason/ntb/wiki +T: git git://github.com/jonmason/ntb.git +F: drivers/ntb/hw/intel/ + NTFS FILESYSTEM M: Anton Altaparmakov L: linux-ntfs-dev@lists.sourceforge.net diff --git a/drivers/net/ntb_netdev.c b/drivers/net/ntb_netdev.c index 6d3bfa62f5ec..3cc316cb7e6b 100644 --- a/drivers/net/ntb_netdev.c +++ b/drivers/net/ntb_netdev.c @@ -5,6 +5,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 Intel Corporation. All rights reserved. + * Copyright (C) 2015 EMC Corporation. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -13,6 +14,7 @@ * BSD LICENSE * * Copyright(c) 2012 Intel Corporation. All rights reserved. + * Copyright (C) 2015 EMC Corporation. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -40,7 +42,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Intel PCIe NTB Network Linux driver + * PCIe NTB Network Linux driver * * Contact Information: * Jon Mason @@ -49,6 +51,7 @@ #include #include #include +#include #include #define NTB_NETDEV_VER "0.7" @@ -70,26 +73,19 @@ struct ntb_netdev { static LIST_HEAD(dev_list); -static void ntb_netdev_event_handler(void *data, int status) +static void ntb_netdev_event_handler(void *data, int link_is_up) { struct net_device *ndev = data; struct ntb_netdev *dev = netdev_priv(ndev); - netdev_dbg(ndev, "Event %x, Link %x\n", status, + netdev_dbg(ndev, "Event %x, Link %x\n", link_is_up, ntb_transport_link_query(dev->qp)); - switch (status) { - case NTB_LINK_DOWN: + if (link_is_up) { + if (ntb_transport_link_query(dev->qp)) + netif_carrier_on(ndev); + } else { netif_carrier_off(ndev); - break; - case NTB_LINK_UP: - if (!ntb_transport_link_query(dev->qp)) - return; - - netif_carrier_on(ndev); - break; - default: - netdev_warn(ndev, "Unsupported event type %d\n", status); } } @@ -160,8 +156,6 @@ static netdev_tx_t ntb_netdev_start_xmit(struct sk_buff *skb, struct ntb_netdev *dev = netdev_priv(ndev); int rc; - netdev_dbg(ndev, "%s: skb len %d\n", __func__, skb->len); - rc = ntb_transport_tx_enqueue(dev->qp, skb, skb->data, skb->len); if (rc) goto err; @@ -322,20 +316,26 @@ static const struct ntb_queue_handlers ntb_netdev_handlers = { .event_handler = ntb_netdev_event_handler, }; -static int ntb_netdev_probe(struct pci_dev *pdev) +static int ntb_netdev_probe(struct device *client_dev) { + struct ntb_dev *ntb; struct net_device *ndev; + struct pci_dev *pdev; struct ntb_netdev *dev; int rc; - ndev = alloc_etherdev(sizeof(struct ntb_netdev)); + ntb = dev_ntb(client_dev->parent); + pdev = ntb->pdev; + if (!pdev) + return -ENODEV; + + ndev = alloc_etherdev(sizeof(*dev)); if (!ndev) return -ENOMEM; dev = netdev_priv(ndev); dev->ndev = ndev; dev->pdev = pdev; - BUG_ON(!dev->pdev); ndev->features = NETIF_F_HIGHDMA; ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE; @@ -349,7 +349,8 @@ static int ntb_netdev_probe(struct pci_dev *pdev) ndev->netdev_ops = &ntb_netdev_ops; ndev->ethtool_ops = &ntb_ethtool_ops; - dev->qp = ntb_transport_create_queue(ndev, pdev, &ntb_netdev_handlers); + dev->qp = ntb_transport_create_queue(ndev, client_dev, + &ntb_netdev_handlers); if (!dev->qp) { rc = -EIO; goto err; @@ -372,12 +373,17 @@ err: return rc; } -static void ntb_netdev_remove(struct pci_dev *pdev) +static void ntb_netdev_remove(struct device *client_dev) { + struct ntb_dev *ntb; struct net_device *ndev; + struct pci_dev *pdev; struct ntb_netdev *dev; bool found = false; + ntb = dev_ntb(client_dev->parent); + pdev = ntb->pdev; + list_for_each_entry(dev, &dev_list, list) { if (dev->pdev == pdev) { found = true; @@ -396,7 +402,7 @@ static void ntb_netdev_remove(struct pci_dev *pdev) free_netdev(ndev); } -static struct ntb_client ntb_netdev_client = { +static struct ntb_transport_client ntb_netdev_client = { .driver.name = KBUILD_MODNAME, .driver.owner = THIS_MODULE, .probe = ntb_netdev_probe, @@ -407,7 +413,7 @@ static int __init ntb_netdev_init_module(void) { int rc; - rc = ntb_register_client_dev(KBUILD_MODNAME); + rc = ntb_transport_register_client_dev(KBUILD_MODNAME); if (rc) return rc; return ntb_transport_register_client(&ntb_netdev_client); @@ -417,6 +423,6 @@ module_init(ntb_netdev_init_module); static void __exit ntb_netdev_exit_module(void) { ntb_transport_unregister_client(&ntb_netdev_client); - ntb_unregister_client_dev(KBUILD_MODNAME); + ntb_transport_unregister_client_dev(KBUILD_MODNAME); } module_exit(ntb_netdev_exit_module); diff --git a/drivers/ntb/Kconfig b/drivers/ntb/Kconfig index f69df793dbe2..53b042429673 100644 --- a/drivers/ntb/Kconfig +++ b/drivers/ntb/Kconfig @@ -1,13 +1,26 @@ -config NTB - tristate "Intel Non-Transparent Bridge support" - depends on PCI - depends on X86 - help - The PCI-E Non-transparent bridge hardware is a point-to-point PCI-E bus - connecting 2 systems. When configured, writes to the device's PCI - mapped memory will be mirrored to a buffer on the remote system. The - ntb Linux driver uses this point-to-point communication as a method to - transfer data from one system to the other. - - If unsure, say N. +menuconfig NTB + tristate "Non-Transparent Bridge support" + depends on PCI + help + The PCI-E Non-transparent bridge hardware is a point-to-point PCI-E bus + connecting 2 systems. When configured, writes to the device's PCI + mapped memory will be mirrored to a buffer on the remote system. The + ntb Linux driver uses this point-to-point communication as a method to + transfer data from one system to the other. + If unsure, say N. + +if NTB + +source "drivers/ntb/hw/Kconfig" + +config NTB_TRANSPORT + tristate "NTB Transport Client" + help + This is a transport driver that enables connected systems to exchange + messages over the ntb hardware. The transport exposes a queue pair api + to client drivers. + + If unsure, say N. + +endif # NTB diff --git a/drivers/ntb/Makefile b/drivers/ntb/Makefile index 712e953a8fda..b9fa663ecfec 100644 --- a/drivers/ntb/Makefile +++ b/drivers/ntb/Makefile @@ -1,4 +1,2 @@ -obj-$(CONFIG_NTB) += ntb.o -obj-$(CONFIG_NTB) += ntb_hw_intel.o - -ntb_hw_intel-objs := hw/intel/ntb_hw_intel.o ntb_transport.o +obj-$(CONFIG_NTB) += ntb.o hw/ +obj-$(CONFIG_NTB_TRANSPORT) += ntb_transport.o diff --git a/drivers/ntb/hw/Kconfig b/drivers/ntb/hw/Kconfig new file mode 100644 index 000000000000..4d5535c4cddf --- /dev/null +++ b/drivers/ntb/hw/Kconfig @@ -0,0 +1 @@ +source "drivers/ntb/hw/intel/Kconfig" diff --git a/drivers/ntb/hw/Makefile b/drivers/ntb/hw/Makefile new file mode 100644 index 000000000000..175d7c92a569 --- /dev/null +++ b/drivers/ntb/hw/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_NTB_INTEL) += intel/ diff --git a/drivers/ntb/hw/intel/Kconfig b/drivers/ntb/hw/intel/Kconfig new file mode 100644 index 000000000000..91f995e33ac6 --- /dev/null +++ b/drivers/ntb/hw/intel/Kconfig @@ -0,0 +1,7 @@ +config NTB_INTEL + tristate "Intel Non-Transparent Bridge support" + depends on X86_64 + help + This driver supports Intel NTB on capable Xeon and Atom hardware. + + If unsure, say N. diff --git a/drivers/ntb/hw/intel/Makefile b/drivers/ntb/hw/intel/Makefile new file mode 100644 index 000000000000..1b434568d2ad --- /dev/null +++ b/drivers/ntb/hw/intel/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_NTB_INTEL) += ntb_hw_intel.o diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c index 044534a995f1..686091756ba4 100644 --- a/drivers/ntb/hw/intel/ntb_hw_intel.c +++ b/drivers/ntb/hw/intel/ntb_hw_intel.c @@ -5,6 +5,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 Intel Corporation. All rights reserved. + * Copyright (C) 2015 EMC Corporation. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -13,6 +14,7 @@ * BSD LICENSE * * Copyright(c) 2012 Intel Corporation. All rights reserved. + * Copyright (C) 2015 EMC Corporation. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -45,6 +47,7 @@ * Contact Information: * Jon Mason */ + #include #include #include @@ -53,99 +56,97 @@ #include #include #include +#include + #include "ntb_hw_intel.h" -#define NTB_NAME "Intel(R) PCI-E Non-Transparent Bridge Driver" -#define NTB_VER "1.0" +#define NTB_NAME "ntb_hw_intel" +#define NTB_DESC "Intel(R) PCI-E Non-Transparent Bridge Driver" +#define NTB_VER "2.0" -MODULE_DESCRIPTION(NTB_NAME); +MODULE_DESCRIPTION(NTB_DESC); MODULE_VERSION(NTB_VER); MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Intel Corporation"); -enum { - NTB_CONN_TRANSPARENT = 0, - NTB_CONN_B2B, - NTB_CONN_RP, -}; - -enum { - NTB_DEV_USD = 0, - NTB_DEV_DSD, -}; - -enum { - SNB_HW = 0, - BWD_HW, -}; - +#define bar0_off(base, bar) ((base) + ((bar) << 2)) +#define bar2_off(base, bar) bar0_off(base, (bar) - 2) + +static int b2b_mw_idx = -1; +module_param(b2b_mw_idx, int, 0644); +MODULE_PARM_DESC(b2b_mw_idx, "Use this mw idx to access the peer ntb. A " + "value of zero or positive starts from first mw idx, and a " + "negative value starts from last mw idx. Both sides MUST " + "set the same value here!"); + +static unsigned int b2b_mw_share; +module_param(b2b_mw_share, uint, 0644); +MODULE_PARM_DESC(b2b_mw_share, "If the b2b mw is large enough, configure the " + "ntb so that the peer ntb only occupies the first half of " + "the mw, so the second half can still be used as a mw. Both " + "sides MUST set the same value here!"); + +static const struct intel_ntb_reg bwd_reg; +static const struct intel_ntb_alt_reg bwd_pri_reg; +static const struct intel_ntb_alt_reg bwd_sec_reg; +static const struct intel_ntb_alt_reg bwd_b2b_reg; +static const struct intel_ntb_xlat_reg bwd_pri_xlat; +static const struct intel_ntb_xlat_reg bwd_sec_xlat; +static const struct intel_ntb_reg snb_reg; +static const struct intel_ntb_alt_reg snb_pri_reg; +static const struct intel_ntb_alt_reg snb_sec_reg; +static const struct intel_ntb_alt_reg snb_b2b_reg; +static const struct intel_ntb_xlat_reg snb_pri_xlat; +static const struct intel_ntb_xlat_reg snb_sec_xlat; +static const struct intel_b2b_addr snb_b2b_usd_addr; +static const struct intel_b2b_addr snb_b2b_dsd_addr; + +static const struct ntb_dev_ops intel_ntb_ops; + +static const struct file_operations intel_ntb_debugfs_info; static struct dentry *debugfs_dir; -#define BWD_LINK_RECOVERY_TIME 500 - -/* Translate memory window 0,1,2 to BAR 2,4,5 */ -#define MW_TO_BAR(mw) (mw == 0 ? 2 : (mw == 1 ? 4 : 5)) - -static const struct pci_device_id ntb_pci_tbl[] = { - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_BWD)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_JSF)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_SNB)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_IVT)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_HSX)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_JSF)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_SNB)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_IVT)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_HSX)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_JSF)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_SNB)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_IVT)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_HSX)}, - {0} -}; -MODULE_DEVICE_TABLE(pci, ntb_pci_tbl); - -static int is_ntb_xeon(struct ntb_device *ndev) +#ifndef ioread64 +#ifdef readq +#define ioread64 readq +#else +#define ioread64 _ioread64 +static inline u64 _ioread64(void __iomem *mmio) { - switch (ndev->pdev->device) { - case PCI_DEVICE_ID_INTEL_NTB_SS_JSF: - case PCI_DEVICE_ID_INTEL_NTB_SS_SNB: - case PCI_DEVICE_ID_INTEL_NTB_SS_IVT: - case PCI_DEVICE_ID_INTEL_NTB_SS_HSX: - case PCI_DEVICE_ID_INTEL_NTB_PS_JSF: - case PCI_DEVICE_ID_INTEL_NTB_PS_SNB: - case PCI_DEVICE_ID_INTEL_NTB_PS_IVT: - case PCI_DEVICE_ID_INTEL_NTB_PS_HSX: - case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF: - case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB: - case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT: - case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX: - return 1; - default: - return 0; - } + u64 low, high; - return 0; + low = ioread32(mmio); + high = ioread32(mmio + sizeof(u32)); + return low | (high << 32); +} +#endif +#endif + +#ifndef iowrite64 +#ifdef writeq +#define iowrite64 writeq +#else +#define iowrite64 _iowrite64 +static inline void _iowrite64(u64 val, void __iomem *mmio) +{ + iowrite32(val, mmio); + iowrite32(val >> 32, mmio + sizeof(u32)); } +#endif +#endif -static int is_ntb_atom(struct ntb_device *ndev) +static inline int pdev_is_bwd(struct pci_dev *pdev) { - switch (ndev->pdev->device) { + switch (pdev->device) { case PCI_DEVICE_ID_INTEL_NTB_B2B_BWD: return 1; - default: - return 0; } - return 0; } -static void ntb_set_errata_flags(struct ntb_device *ndev) +static inline int pdev_is_snb(struct pci_dev *pdev) { - switch (ndev->pdev->device) { - /* - * this workaround applies to all platform up to IvyBridge - * Haswell has splitbar support and use a different workaround - */ + switch (pdev->device) { case PCI_DEVICE_ID_INTEL_NTB_SS_JSF: case PCI_DEVICE_ID_INTEL_NTB_SS_SNB: case PCI_DEVICE_ID_INTEL_NTB_SS_IVT: @@ -158,1737 +159,1957 @@ static void ntb_set_errata_flags(struct ntb_device *ndev) case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB: case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT: case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX: - ndev->wa_flags |= WA_SNB_ERR; - break; + return 1; } + return 0; } -/** - * ntb_register_event_callback() - register event callback - * @ndev: pointer to ntb_device instance - * @func: callback function to register - * - * This function registers a callback for any HW driver events such as link - * up/down, power management notices and etc. - * - * RETURNS: An appropriate -ERRNO error value on error, or zero for success. - */ -int ntb_register_event_callback(struct ntb_device *ndev, - void (*func)(void *handle, - enum ntb_hw_event event)) +static inline void ndev_reset_unsafe_flags(struct intel_ntb_dev *ndev) { - if (ndev->event_cb) - return -EINVAL; - - ndev->event_cb = func; - - return 0; + ndev->unsafe_flags = 0; + ndev->unsafe_flags_ignore = 0; + + /* Only B2B has a workaround to avoid SDOORBELL */ + if (ndev->hwerr_flags & NTB_HWERR_SDOORBELL_LOCKUP) + if (!ntb_topo_is_b2b(ndev->ntb.topo)) + ndev->unsafe_flags |= NTB_UNSAFE_DB; + + /* No low level workaround to avoid SB01BASE */ + if (ndev->hwerr_flags & NTB_HWERR_SB01BASE_LOCKUP) { + ndev->unsafe_flags |= NTB_UNSAFE_DB; + ndev->unsafe_flags |= NTB_UNSAFE_SPAD; + } } -/** - * ntb_unregister_event_callback() - unregisters the event callback - * @ndev: pointer to ntb_device instance - * - * This function unregisters the existing callback from transport - */ -void ntb_unregister_event_callback(struct ntb_device *ndev) +static inline int ndev_is_unsafe(struct intel_ntb_dev *ndev, + unsigned long flag) { - ndev->event_cb = NULL; + return !!(flag & ndev->unsafe_flags & ~ndev->unsafe_flags_ignore); } -static void ntb_irq_work(unsigned long data) +static inline int ndev_ignore_unsafe(struct intel_ntb_dev *ndev, + unsigned long flag) { - struct ntb_db_cb *db_cb = (struct ntb_db_cb *)data; - int rc; + flag &= ndev->unsafe_flags; + ndev->unsafe_flags_ignore |= flag; - rc = db_cb->callback(db_cb->data, db_cb->db_num); - if (rc) - tasklet_schedule(&db_cb->irq_work); - else { - struct ntb_device *ndev = db_cb->ndev; - unsigned long mask; - - mask = readw(ndev->reg_ofs.ldb_mask); - clear_bit(db_cb->db_num * ndev->bits_per_vector, &mask); - writew(mask, ndev->reg_ofs.ldb_mask); - } + return !!flag; } -/** - * ntb_register_db_callback() - register a callback for doorbell interrupt - * @ndev: pointer to ntb_device instance - * @idx: doorbell index to register callback, zero based - * @data: pointer to be returned to caller with every callback - * @func: callback function to register - * - * This function registers a callback function for the doorbell interrupt - * on the primary side. The function will unmask the doorbell as well to - * allow interrupt. - * - * RETURNS: An appropriate -ERRNO error value on error, or zero for success. - */ -int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx, - void *data, int (*func)(void *data, int db_num)) +static int ndev_mw_to_bar(struct intel_ntb_dev *ndev, int idx) { - unsigned long mask; - - if (idx >= ndev->max_cbs || ndev->db_cb[idx].callback) { - dev_warn(&ndev->pdev->dev, "Invalid Index.\n"); + if (idx < 0 || idx > ndev->mw_count) return -EINVAL; - } + return ndev->reg->mw_bar[idx]; +} - ndev->db_cb[idx].callback = func; - ndev->db_cb[idx].data = data; - ndev->db_cb[idx].ndev = ndev; +static inline int ndev_db_addr(struct intel_ntb_dev *ndev, + phys_addr_t *db_addr, resource_size_t *db_size, + phys_addr_t reg_addr, unsigned long reg) +{ + WARN_ON_ONCE(ndev_is_unsafe(ndev, NTB_UNSAFE_DB)); - tasklet_init(&ndev->db_cb[idx].irq_work, ntb_irq_work, - (unsigned long) &ndev->db_cb[idx]); + if (db_addr) { + *db_addr = reg_addr + reg; + dev_dbg(ndev_dev(ndev), "Peer db addr %llx\n", *db_addr); + } - /* unmask interrupt */ - mask = readw(ndev->reg_ofs.ldb_mask); - clear_bit(idx * ndev->bits_per_vector, &mask); - writew(mask, ndev->reg_ofs.ldb_mask); + if (db_size) { + *db_size = ndev->reg->db_size; + dev_dbg(ndev_dev(ndev), "Peer db size %llx\n", *db_size); + } return 0; } -/** - * ntb_unregister_db_callback() - unregister a callback for doorbell interrupt - * @ndev: pointer to ntb_device instance - * @idx: doorbell index to register callback, zero based - * - * This function unregisters a callback function for the doorbell interrupt - * on the primary side. The function will also mask the said doorbell. - */ -void ntb_unregister_db_callback(struct ntb_device *ndev, unsigned int idx) +static inline u64 ndev_db_read(struct intel_ntb_dev *ndev, + void __iomem *mmio) { - unsigned long mask; + WARN_ON_ONCE(ndev_is_unsafe(ndev, NTB_UNSAFE_DB)); - if (idx >= ndev->max_cbs || !ndev->db_cb[idx].callback) - return; + return ndev->reg->db_ioread(mmio); +} + +static inline int ndev_db_write(struct intel_ntb_dev *ndev, u64 db_bits, + void __iomem *mmio) +{ + WARN_ON_ONCE(ndev_is_unsafe(ndev, NTB_UNSAFE_DB)); - mask = readw(ndev->reg_ofs.ldb_mask); - set_bit(idx * ndev->bits_per_vector, &mask); - writew(mask, ndev->reg_ofs.ldb_mask); + if (db_bits & ~ndev->db_valid_mask) + return -EINVAL; - tasklet_disable(&ndev->db_cb[idx].irq_work); + ndev->reg->db_iowrite(db_bits, mmio); - ndev->db_cb[idx].callback = NULL; + return 0; } -/** - * ntb_find_transport() - find the transport pointer - * @transport: pointer to pci device - * - * Given the pci device pointer, return the transport pointer passed in when - * the transport attached when it was inited. - * - * RETURNS: pointer to transport. - */ -void *ntb_find_transport(struct pci_dev *pdev) +static inline int ndev_db_set_mask(struct intel_ntb_dev *ndev, u64 db_bits, + void __iomem *mmio) { - struct ntb_device *ndev = pci_get_drvdata(pdev); - return ndev->ntb_transport; -} + unsigned long irqflags; -/** - * ntb_register_transport() - Register NTB transport with NTB HW driver - * @transport: transport identifier - * - * This function allows a transport to reserve the hardware driver for - * NTB usage. - * - * RETURNS: pointer to ntb_device, NULL on error. - */ -struct ntb_device *ntb_register_transport(struct pci_dev *pdev, void *transport) -{ - struct ntb_device *ndev = pci_get_drvdata(pdev); + WARN_ON_ONCE(ndev_is_unsafe(ndev, NTB_UNSAFE_DB)); + + if (db_bits & ~ndev->db_valid_mask) + return -EINVAL; - if (ndev->ntb_transport) - return NULL; + spin_lock_irqsave(&ndev->db_mask_lock, irqflags); + { + ndev->db_mask |= db_bits; + ndev->reg->db_iowrite(ndev->db_mask, mmio); + } + spin_unlock_irqrestore(&ndev->db_mask_lock, irqflags); - ndev->ntb_transport = transport; - return ndev; + return 0; } -/** - * ntb_unregister_transport() - Unregister the transport with the NTB HW driver - * @ndev - ntb_device of the transport to be freed - * - * This function unregisters the transport from the HW driver and performs any - * necessary cleanups. - */ -void ntb_unregister_transport(struct ntb_device *ndev) +static inline int ndev_db_clear_mask(struct intel_ntb_dev *ndev, u64 db_bits, + void __iomem *mmio) { - int i; + unsigned long irqflags; - if (!ndev->ntb_transport) - return; + WARN_ON_ONCE(ndev_is_unsafe(ndev, NTB_UNSAFE_DB)); + + if (db_bits & ~ndev->db_valid_mask) + return -EINVAL; - for (i = 0; i < ndev->max_cbs; i++) - ntb_unregister_db_callback(ndev, i); + spin_lock_irqsave(&ndev->db_mask_lock, irqflags); + { + ndev->db_mask &= ~db_bits; + ndev->reg->db_iowrite(ndev->db_mask, mmio); + } + spin_unlock_irqrestore(&ndev->db_mask_lock, irqflags); - ntb_unregister_event_callback(ndev); - ndev->ntb_transport = NULL; + return 0; } -/** - * ntb_write_local_spad() - write to the secondary scratchpad register - * @ndev: pointer to ntb_device instance - * @idx: index to the scratchpad register, 0 based - * @val: the data value to put into the register - * - * This function allows writing of a 32bit value to the indexed scratchpad - * register. This writes over the data mirrored to the local scratchpad register - * by the remote system. - * - * RETURNS: An appropriate -ERRNO error value on error, or zero for success. - */ -int ntb_write_local_spad(struct ntb_device *ndev, unsigned int idx, u32 val) +static inline int ndev_vec_mask(struct intel_ntb_dev *ndev, int db_vector) { - if (idx >= ndev->limits.max_spads) - return -EINVAL; + u64 shift, mask; - dev_dbg(&ndev->pdev->dev, "Writing %x to local scratch pad index %d\n", - val, idx); - writel(val, ndev->reg_ofs.spad_read + idx * 4); + shift = ndev->db_vec_shift; + mask = BIT_ULL(shift) - 1; - return 0; + return mask << (shift * db_vector); } -/** - * ntb_read_local_spad() - read from the primary scratchpad register - * @ndev: pointer to ntb_device instance - * @idx: index to scratchpad register, 0 based - * @val: pointer to 32bit integer for storing the register value - * - * This function allows reading of the 32bit scratchpad register on - * the primary (internal) side. This allows the local system to read data - * written and mirrored to the scratchpad register by the remote system. - * - * RETURNS: An appropriate -ERRNO error value on error, or zero for success. - */ -int ntb_read_local_spad(struct ntb_device *ndev, unsigned int idx, u32 *val) +static inline int ndev_spad_addr(struct intel_ntb_dev *ndev, int idx, + phys_addr_t *spad_addr, phys_addr_t reg_addr, + unsigned long reg) { - if (idx >= ndev->limits.max_spads) + WARN_ON_ONCE(ndev_is_unsafe(ndev, NTB_UNSAFE_SPAD)); + + if (idx < 0 || idx >= ndev->spad_count) return -EINVAL; - *val = readl(ndev->reg_ofs.spad_write + idx * 4); - dev_dbg(&ndev->pdev->dev, - "Reading %x from local scratch pad index %d\n", *val, idx); + if (spad_addr) { + *spad_addr = reg_addr + reg + (idx << 2); + dev_dbg(ndev_dev(ndev), "Peer spad addr %llx\n", *spad_addr); + } return 0; } -/** - * ntb_write_remote_spad() - write to the secondary scratchpad register - * @ndev: pointer to ntb_device instance - * @idx: index to the scratchpad register, 0 based - * @val: the data value to put into the register - * - * This function allows writing of a 32bit value to the indexed scratchpad - * register. The register resides on the secondary (external) side. This allows - * the local system to write data to be mirrored to the remote systems - * scratchpad register. - * - * RETURNS: An appropriate -ERRNO error value on error, or zero for success. - */ -int ntb_write_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 val) +static inline u32 ndev_spad_read(struct intel_ntb_dev *ndev, int idx, + void __iomem *mmio) { - if (idx >= ndev->limits.max_spads) - return -EINVAL; + WARN_ON_ONCE(ndev_is_unsafe(ndev, NTB_UNSAFE_SPAD)); - dev_dbg(&ndev->pdev->dev, "Writing %x to remote scratch pad index %d\n", - val, idx); - writel(val, ndev->reg_ofs.spad_write + idx * 4); + if (idx < 0 || idx >= ndev->spad_count) + return 0; - return 0; + return ioread32(mmio + (idx << 2)); } -/** - * ntb_read_remote_spad() - read from the primary scratchpad register - * @ndev: pointer to ntb_device instance - * @idx: index to scratchpad register, 0 based - * @val: pointer to 32bit integer for storing the register value - * - * This function allows reading of the 32bit scratchpad register on - * the primary (internal) side. This alloows the local system to read the data - * it wrote to be mirrored on the remote system. - * - * RETURNS: An appropriate -ERRNO error value on error, or zero for success. - */ -int ntb_read_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 *val) +static inline int ndev_spad_write(struct intel_ntb_dev *ndev, int idx, u32 val, + void __iomem *mmio) { - if (idx >= ndev->limits.max_spads) + WARN_ON_ONCE(ndev_is_unsafe(ndev, NTB_UNSAFE_SPAD)); + + if (idx < 0 || idx >= ndev->spad_count) return -EINVAL; - *val = readl(ndev->reg_ofs.spad_read + idx * 4); - dev_dbg(&ndev->pdev->dev, - "Reading %x from remote scratch pad index %d\n", *val, idx); + iowrite32(val, mmio + (idx << 2)); return 0; } -/** - * ntb_get_mw_base() - get addr for the NTB memory window - * @ndev: pointer to ntb_device instance - * @mw: memory window number - * - * This function provides the base address of the memory window specified. - * - * RETURNS: address, or NULL on error. - */ -resource_size_t ntb_get_mw_base(struct ntb_device *ndev, unsigned int mw) +static irqreturn_t ndev_interrupt(struct intel_ntb_dev *ndev, int vec) { - if (mw >= ntb_max_mw(ndev)) - return 0; + u64 vec_mask; + + vec_mask = ndev_vec_mask(ndev, vec); + + dev_dbg(ndev_dev(ndev), "vec %d vec_mask %llx\n", vec, vec_mask); - return pci_resource_start(ndev->pdev, MW_TO_BAR(mw)); + ndev->last_ts = jiffies; + + if (vec_mask & ndev->db_link_mask) { + if (ndev->reg->poll_link(ndev)) + ntb_link_event(&ndev->ntb); + } + + if (vec_mask & ndev->db_valid_mask) + ntb_db_event(&ndev->ntb, vec); + + return IRQ_HANDLED; } -/** - * ntb_get_mw_vbase() - get virtual addr for the NTB memory window - * @ndev: pointer to ntb_device instance - * @mw: memory window number - * - * This function provides the base virtual address of the memory window - * specified. - * - * RETURNS: pointer to virtual address, or NULL on error. - */ -void __iomem *ntb_get_mw_vbase(struct ntb_device *ndev, unsigned int mw) +static irqreturn_t ndev_vec_isr(int irq, void *dev) { - if (mw >= ntb_max_mw(ndev)) - return NULL; + struct intel_ntb_vec *nvec = dev; - return ndev->mw[mw].vbase; + return ndev_interrupt(nvec->ndev, nvec->num); } -/** - * ntb_get_mw_size() - return size of NTB memory window - * @ndev: pointer to ntb_device instance - * @mw: memory window number - * - * This function provides the physical size of the memory window specified - * - * RETURNS: the size of the memory window or zero on error - */ -u64 ntb_get_mw_size(struct ntb_device *ndev, unsigned int mw) +static irqreturn_t ndev_irq_isr(int irq, void *dev) { - if (mw >= ntb_max_mw(ndev)) - return 0; + struct intel_ntb_dev *ndev = dev; - return ndev->mw[mw].bar_sz; + return ndev_interrupt(ndev, irq - ndev_pdev(ndev)->irq); } -/** - * ntb_set_mw_addr - set the memory window address - * @ndev: pointer to ntb_device instance - * @mw: memory window number - * @addr: base address for data - * - * This function sets the base physical address of the memory window. This - * memory address is where data from the remote system will be transfered into - * or out of depending on how the transport is configured. - */ -void ntb_set_mw_addr(struct ntb_device *ndev, unsigned int mw, u64 addr) +static int ndev_init_isr(struct intel_ntb_dev *ndev, + int msix_min, int msix_max, + int msix_shift, int total_shift) { - if (mw >= ntb_max_mw(ndev)) - return; + struct pci_dev *pdev; + int rc, i, msix_count; - dev_dbg(&ndev->pdev->dev, "Writing addr %Lx to BAR %d\n", addr, - MW_TO_BAR(mw)); + pdev = ndev_pdev(ndev); - ndev->mw[mw].phys_addr = addr; + /* Mask all doorbell interrupts */ + ndev->db_mask = ndev->db_valid_mask; + ndev->reg->db_iowrite(ndev->db_mask, + ndev->self_mmio + + ndev->self_reg->db_mask); - switch (MW_TO_BAR(mw)) { - case NTB_BAR_23: - writeq(addr, ndev->reg_ofs.bar2_xlat); - break; - case NTB_BAR_4: - if (ndev->split_bar) - writel(addr, ndev->reg_ofs.bar4_xlat); - else - writeq(addr, ndev->reg_ofs.bar4_xlat); - break; - case NTB_BAR_5: - writel(addr, ndev->reg_ofs.bar5_xlat); - break; + /* Try to set up msix irq */ + + ndev->vec = kcalloc(msix_max, sizeof(*ndev->vec), GFP_KERNEL); + if (!ndev->vec) + goto err_msix_vec_alloc; + + ndev->msix = kcalloc(msix_max, sizeof(*ndev->msix), GFP_KERNEL); + if (!ndev->msix) + goto err_msix_alloc; + + for (i = 0; i < msix_max; ++i) + ndev->msix[i].entry = i; + + msix_count = pci_enable_msix_range(pdev, ndev->msix, + msix_min, msix_max); + if (msix_count < 0) + goto err_msix_enable; + + for (i = 0; i < msix_count; ++i) { + ndev->vec[i].ndev = ndev; + ndev->vec[i].num = i; + rc = request_irq(ndev->msix[i].vector, ndev_vec_isr, 0, + "ndev_vec_isr", &ndev->vec[i]); + if (rc) + goto err_msix_request; } -} -/** - * ntb_ring_doorbell() - Set the doorbell on the secondary/external side - * @ndev: pointer to ntb_device instance - * @db: doorbell to ring - * - * This function allows triggering of a doorbell on the secondary/external - * side that will initiate an interrupt on the remote host - * - * RETURNS: An appropriate -ERRNO error value on error, or zero for success. - */ -void ntb_ring_doorbell(struct ntb_device *ndev, unsigned int db) -{ - dev_dbg(&ndev->pdev->dev, "%s: ringing doorbell %d\n", __func__, db); + dev_dbg(ndev_dev(ndev), "Using msix interrupts\n"); + ndev->db_vec_count = msix_count; + ndev->db_vec_shift = msix_shift; + return 0; - if (ndev->hw_type == BWD_HW) - writeq((u64) 1 << db, ndev->reg_ofs.rdb); - else - writew(((1 << ndev->bits_per_vector) - 1) << - (db * ndev->bits_per_vector), ndev->reg_ofs.rdb); -} +err_msix_request: + while (i-- > 0) + free_irq(ndev->msix[i].vector, ndev); + pci_disable_msix(pdev); +err_msix_enable: + kfree(ndev->msix); +err_msix_alloc: + kfree(ndev->vec); +err_msix_vec_alloc: + ndev->msix = NULL; + ndev->vec = NULL; -static void bwd_recover_link(struct ntb_device *ndev) -{ - u32 status; + /* Try to set up msi irq */ - /* Driver resets the NTB ModPhy lanes - magic! */ - writeb(0xe0, ndev->reg_base + BWD_MODPHY_PCSREG6); - writeb(0x40, ndev->reg_base + BWD_MODPHY_PCSREG4); - writeb(0x60, ndev->reg_base + BWD_MODPHY_PCSREG4); - writeb(0x60, ndev->reg_base + BWD_MODPHY_PCSREG6); + rc = pci_enable_msi(pdev); + if (rc) + goto err_msi_enable; - /* Driver waits 100ms to allow the NTB ModPhy to settle */ - msleep(100); + rc = request_irq(pdev->irq, ndev_irq_isr, 0, + "ndev_irq_isr", ndev); + if (rc) + goto err_msi_request; - /* Clear AER Errors, write to clear */ - status = readl(ndev->reg_base + BWD_ERRCORSTS_OFFSET); - dev_dbg(&ndev->pdev->dev, "ERRCORSTS = %x\n", status); - status &= PCI_ERR_COR_REP_ROLL; - writel(status, ndev->reg_base + BWD_ERRCORSTS_OFFSET); + dev_dbg(ndev_dev(ndev), "Using msi interrupts\n"); + ndev->db_vec_count = 1; + ndev->db_vec_shift = total_shift; + return 0; - /* Clear unexpected electrical idle event in LTSSM, write to clear */ - status = readl(ndev->reg_base + BWD_LTSSMERRSTS0_OFFSET); - dev_dbg(&ndev->pdev->dev, "LTSSMERRSTS0 = %x\n", status); - status |= BWD_LTSSMERRSTS0_UNEXPECTEDEI; - writel(status, ndev->reg_base + BWD_LTSSMERRSTS0_OFFSET); +err_msi_request: + pci_disable_msi(pdev); +err_msi_enable: - /* Clear DeSkew Buffer error, write to clear */ - status = readl(ndev->reg_base + BWD_DESKEWSTS_OFFSET); - dev_dbg(&ndev->pdev->dev, "DESKEWSTS = %x\n", status); - status |= BWD_DESKEWSTS_DBERR; - writel(status, ndev->reg_base + BWD_DESKEWSTS_OFFSET); + /* Try to set up intx irq */ - status = readl(ndev->reg_base + BWD_IBSTERRRCRVSTS0_OFFSET); - dev_dbg(&ndev->pdev->dev, "IBSTERRRCRVSTS0 = %x\n", status); - status &= BWD_IBIST_ERR_OFLOW; - writel(status, ndev->reg_base + BWD_IBSTERRRCRVSTS0_OFFSET); + pci_intx(pdev, 1); - /* Releases the NTB state machine to allow the link to retrain */ - status = readl(ndev->reg_base + BWD_LTSSMSTATEJMP_OFFSET); - dev_dbg(&ndev->pdev->dev, "LTSSMSTATEJMP = %x\n", status); - status &= ~BWD_LTSSMSTATEJMP_FORCEDETECT; - writel(status, ndev->reg_base + BWD_LTSSMSTATEJMP_OFFSET); + rc = request_irq(pdev->irq, ndev_irq_isr, IRQF_SHARED, + "ndev_irq_isr", ndev); + if (rc) + goto err_intx_request; + + dev_dbg(ndev_dev(ndev), "Using intx interrupts\n"); + ndev->db_vec_count = 1; + ndev->db_vec_shift = total_shift; + return 0; + +err_intx_request: + return rc; } -static void ntb_link_event(struct ntb_device *ndev, int link_state) +static void ndev_deinit_isr(struct intel_ntb_dev *ndev) { - unsigned int event; + struct pci_dev *pdev; + int i; - if (ndev->link_status == link_state) - return; + pdev = ndev_pdev(ndev); - if (link_state == NTB_LINK_UP) { - u16 status; - - dev_info(&ndev->pdev->dev, "Link Up\n"); - ndev->link_status = NTB_LINK_UP; - event = NTB_EVENT_HW_LINK_UP; - - if (is_ntb_atom(ndev) || - ndev->conn_type == NTB_CONN_TRANSPARENT) - status = readw(ndev->reg_ofs.lnk_stat); - else { - int rc = pci_read_config_word(ndev->pdev, - SNB_LINK_STATUS_OFFSET, - &status); - if (rc) - return; - } + /* Mask all doorbell interrupts */ + ndev->db_mask = ndev->db_valid_mask; + ndev->reg->db_iowrite(ndev->db_mask, + ndev->self_mmio + + ndev->self_reg->db_mask); - ndev->link_width = (status & NTB_LINK_WIDTH_MASK) >> 4; - ndev->link_speed = (status & NTB_LINK_SPEED_MASK); - dev_info(&ndev->pdev->dev, "Link Width %d, Link Speed %d\n", - ndev->link_width, ndev->link_speed); + if (ndev->msix) { + i = ndev->db_vec_count; + while (i--) + free_irq(ndev->msix[i].vector, &ndev->vec[i]); + pci_disable_msix(pdev); + kfree(ndev->msix); + kfree(ndev->vec); } else { - dev_info(&ndev->pdev->dev, "Link Down\n"); - ndev->link_status = NTB_LINK_DOWN; - event = NTB_EVENT_HW_LINK_DOWN; - /* Don't modify link width/speed, we need it in link recovery */ + free_irq(pdev->irq, ndev); + if (pci_dev_msi_enabled(pdev)) + pci_disable_msi(pdev); } - - /* notify the upper layer if we have an event change */ - if (ndev->event_cb) - ndev->event_cb(ndev->ntb_transport, event); } -static int ntb_link_status(struct ntb_device *ndev) +static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf, + size_t count, loff_t *offp) { - int link_state; + struct intel_ntb_dev *ndev; + void __iomem *mmio; + char *buf; + size_t buf_size; + ssize_t ret, off; + union { u64 v64; u32 v32; u16 v16; } u; - if (is_ntb_atom(ndev)) { - u32 ntb_cntl; + ndev = filp->private_data; + mmio = ndev->self_mmio; - ntb_cntl = readl(ndev->reg_ofs.lnk_cntl); - if (ntb_cntl & BWD_CNTL_LINK_DOWN) - link_state = NTB_LINK_DOWN; - else - link_state = NTB_LINK_UP; - } else { - u16 status; - int rc; + buf_size = min(count, 0x800ul); - rc = pci_read_config_word(ndev->pdev, SNB_LINK_STATUS_OFFSET, - &status); - if (rc) - return rc; + buf = kmalloc(buf_size, GFP_KERNEL); + if (!buf) + return -ENOMEM; - if (status & NTB_LINK_STATUS_ACTIVE) - link_state = NTB_LINK_UP; - else - link_state = NTB_LINK_DOWN; - } + off = 0; - ntb_link_event(ndev, link_state); + off += scnprintf(buf + off, buf_size - off, + "NTB Device Information:\n"); - return 0; -} + off += scnprintf(buf + off, buf_size - off, + "Connection Topology -\t%s\n", + ntb_topo_string(ndev->ntb.topo)); -static void bwd_link_recovery(struct work_struct *work) -{ - struct ntb_device *ndev = container_of(work, struct ntb_device, - lr_timer.work); - u32 status32; + off += scnprintf(buf + off, buf_size - off, + "B2B Offset -\t\t%#lx\n", ndev->b2b_off); + off += scnprintf(buf + off, buf_size - off, + "B2B MW Idx -\t\t%d\n", ndev->b2b_idx); + off += scnprintf(buf + off, buf_size - off, + "BAR4 Split -\t\t%s\n", + ndev->bar4_split ? "yes" : "no"); - bwd_recover_link(ndev); - /* There is a potential race between the 2 NTB devices recovering at the - * same time. If the times are the same, the link will not recover and - * the driver will be stuck in this loop forever. Add a random interval - * to the recovery time to prevent this race. - */ - msleep(BWD_LINK_RECOVERY_TIME + prandom_u32() % BWD_LINK_RECOVERY_TIME); - - status32 = readl(ndev->reg_base + BWD_LTSSMSTATEJMP_OFFSET); - if (status32 & BWD_LTSSMSTATEJMP_FORCEDETECT) - goto retry; - - status32 = readl(ndev->reg_base + BWD_IBSTERRRCRVSTS0_OFFSET); - if (status32 & BWD_IBIST_ERR_OFLOW) - goto retry; - - status32 = readl(ndev->reg_ofs.lnk_cntl); - if (!(status32 & BWD_CNTL_LINK_DOWN)) { - unsigned char speed, width; - u16 status16; - - status16 = readw(ndev->reg_ofs.lnk_stat); - width = (status16 & NTB_LINK_WIDTH_MASK) >> 4; - speed = (status16 & NTB_LINK_SPEED_MASK); - if (ndev->link_width != width || ndev->link_speed != speed) - goto retry; + off += scnprintf(buf + off, buf_size - off, + "NTB CTL -\t\t%#06x\n", ndev->ntb_ctl); + off += scnprintf(buf + off, buf_size - off, + "LNK STA -\t\t%#06x\n", ndev->lnk_sta); + + if (!ndev->reg->link_is_up(ndev)) { + off += scnprintf(buf + off, buf_size - off, + "Link Status -\t\tDown\n"); + } else { + off += scnprintf(buf + off, buf_size - off, + "Link Status -\t\tUp\n"); + off += scnprintf(buf + off, buf_size - off, + "Link Speed -\t\tPCI-E Gen %u\n", + NTB_LNK_STA_SPEED(ndev->lnk_sta)); + off += scnprintf(buf + off, buf_size - off, + "Link Width -\t\tx%u\n", + NTB_LNK_STA_WIDTH(ndev->lnk_sta)); } - schedule_delayed_work(&ndev->hb_timer, NTB_HB_TIMEOUT); - return; + off += scnprintf(buf + off, buf_size - off, + "Memory Window Count -\t%u\n", ndev->mw_count); + off += scnprintf(buf + off, buf_size - off, + "Scratchpad Count -\t%u\n", ndev->spad_count); + off += scnprintf(buf + off, buf_size - off, + "Doorbell Count -\t%u\n", ndev->db_count); + off += scnprintf(buf + off, buf_size - off, + "Doorbell Vector Count -\t%u\n", ndev->db_vec_count); + off += scnprintf(buf + off, buf_size - off, + "Doorbell Vector Shift -\t%u\n", ndev->db_vec_shift); + + off += scnprintf(buf + off, buf_size - off, + "Doorbell Valid Mask -\t%#llx\n", ndev->db_valid_mask); + off += scnprintf(buf + off, buf_size - off, + "Doorbell Link Mask -\t%#llx\n", ndev->db_link_mask); + off += scnprintf(buf + off, buf_size - off, + "Doorbell Mask Cached -\t%#llx\n", ndev->db_mask); + + u.v64 = ndev_db_read(ndev, mmio + ndev->self_reg->db_mask); + off += scnprintf(buf + off, buf_size - off, + "Doorbell Mask -\t\t%#llx\n", u.v64); + + u.v64 = ndev_db_read(ndev, mmio + ndev->self_reg->db_bell); + off += scnprintf(buf + off, buf_size - off, + "Doorbell Bell -\t\t%#llx\n", u.v64); + + off += scnprintf(buf + off, buf_size - off, + "\nNTB Incoming XLAT:\n"); + + u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_xlat, 2)); + off += scnprintf(buf + off, buf_size - off, + "XLAT23 -\t\t%#018llx\n", u.v64); + + u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_xlat, 4)); + off += scnprintf(buf + off, buf_size - off, + "XLAT45 -\t\t%#018llx\n", u.v64); + + u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_limit, 2)); + off += scnprintf(buf + off, buf_size - off, + "LMT23 -\t\t\t%#018llx\n", u.v64); + + u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_limit, 4)); + off += scnprintf(buf + off, buf_size - off, + "LMT45 -\t\t\t%#018llx\n", u.v64); + + if (pdev_is_snb(ndev->ntb.pdev)) { + if (ntb_topo_is_b2b(ndev->ntb.topo)) { + off += scnprintf(buf + off, buf_size - off, + "\nNTB Outgoing B2B XLAT:\n"); + + u.v64 = ioread64(mmio + SNB_PBAR23XLAT_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "B2B XLAT23 -\t\t%#018llx\n", u.v64); + + u.v64 = ioread64(mmio + SNB_PBAR45XLAT_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "B2B XLAT45 -\t\t%#018llx\n", u.v64); + + u.v64 = ioread64(mmio + SNB_PBAR23LMT_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "B2B LMT23 -\t\t%#018llx\n", u.v64); + + u.v64 = ioread64(mmio + SNB_PBAR45LMT_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "B2B LMT45 -\t\t%#018llx\n", u.v64); + + off += scnprintf(buf + off, buf_size - off, + "\nNTB Secondary BAR:\n"); + + u.v64 = ioread64(mmio + SNB_SBAR0BASE_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "SBAR01 -\t\t%#018llx\n", u.v64); + + u.v64 = ioread64(mmio + SNB_SBAR23BASE_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "SBAR23 -\t\t%#018llx\n", u.v64); + + u.v64 = ioread64(mmio + SNB_SBAR45BASE_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "SBAR45 -\t\t%#018llx\n", u.v64); + } + + off += scnprintf(buf + off, buf_size - off, + "\nSNB NTB Statistics:\n"); + + u.v16 = ioread16(mmio + SNB_USMEMMISS_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "Upstream Memory Miss -\t%u\n", u.v16); + + off += scnprintf(buf + off, buf_size - off, + "\nSNB NTB Hardware Errors:\n"); + + if (!pci_read_config_word(ndev->ntb.pdev, + SNB_DEVSTS_OFFSET, &u.v16)) + off += scnprintf(buf + off, buf_size - off, + "DEVSTS -\t\t%#06x\n", u.v16); + + if (!pci_read_config_word(ndev->ntb.pdev, + SNB_LINK_STATUS_OFFSET, &u.v16)) + off += scnprintf(buf + off, buf_size - off, + "LNKSTS -\t\t%#06x\n", u.v16); -retry: - schedule_delayed_work(&ndev->lr_timer, NTB_HB_TIMEOUT); + if (!pci_read_config_dword(ndev->ntb.pdev, + SNB_UNCERRSTS_OFFSET, &u.v32)) + off += scnprintf(buf + off, buf_size - off, + "UNCERRSTS -\t\t%#06x\n", u.v32); + + if (!pci_read_config_dword(ndev->ntb.pdev, + SNB_CORERRSTS_OFFSET, &u.v32)) + off += scnprintf(buf + off, buf_size - off, + "CORERRSTS -\t\t%#06x\n", u.v32); + } + + ret = simple_read_from_buffer(ubuf, count, offp, buf, off); + kfree(buf); + return ret; } -/* BWD doesn't have link status interrupt, poll on that platform */ -static void bwd_link_poll(struct work_struct *work) +static void ndev_init_debugfs(struct intel_ntb_dev *ndev) { - struct ntb_device *ndev = container_of(work, struct ntb_device, - hb_timer.work); - unsigned long ts = jiffies; - - /* If we haven't gotten an interrupt in a while, check the BWD link - * status bit - */ - if (ts > ndev->last_ts + NTB_HB_TIMEOUT) { - int rc = ntb_link_status(ndev); - if (rc) - dev_err(&ndev->pdev->dev, - "Error determining link status\n"); - - /* Check to see if a link error is the cause of the link down */ - if (ndev->link_status == NTB_LINK_DOWN) { - u32 status32 = readl(ndev->reg_base + - BWD_LTSSMSTATEJMP_OFFSET); - if (status32 & BWD_LTSSMSTATEJMP_FORCEDETECT) { - schedule_delayed_work(&ndev->lr_timer, 0); - return; - } - } + if (!debugfs_dir) { + ndev->debugfs_dir = NULL; + ndev->debugfs_info = NULL; + } else { + ndev->debugfs_dir = + debugfs_create_dir(ndev_name(ndev), debugfs_dir); + if (!ndev->debugfs_dir) + ndev->debugfs_info = NULL; + else + ndev->debugfs_info = + debugfs_create_file("info", S_IRUSR, + ndev->debugfs_dir, ndev, + &intel_ntb_debugfs_info); } +} - schedule_delayed_work(&ndev->hb_timer, NTB_HB_TIMEOUT); +static void ndev_deinit_debugfs(struct intel_ntb_dev *ndev) +{ + debugfs_remove_recursive(ndev->debugfs_dir); } -static int ntb_xeon_setup(struct ntb_device *ndev) +static int intel_ntb_mw_count(struct ntb_dev *ntb) { - switch (ndev->conn_type) { - case NTB_CONN_B2B: - ndev->reg_ofs.ldb = ndev->reg_base + SNB_PDOORBELL_OFFSET; - ndev->reg_ofs.ldb_mask = ndev->reg_base + SNB_PDBMSK_OFFSET; - ndev->reg_ofs.spad_read = ndev->reg_base + SNB_SPAD_OFFSET; - ndev->reg_ofs.bar2_xlat = ndev->reg_base + SNB_SBAR2XLAT_OFFSET; - ndev->reg_ofs.bar4_xlat = ndev->reg_base + SNB_SBAR4XLAT_OFFSET; - if (ndev->split_bar) - ndev->reg_ofs.bar5_xlat = - ndev->reg_base + SNB_SBAR5XLAT_OFFSET; - ndev->limits.max_spads = SNB_MAX_B2B_SPADS; + return ntb_ndev(ntb)->mw_count; +} - /* There is a Xeon hardware errata related to writes to - * SDOORBELL or B2BDOORBELL in conjunction with inbound access - * to NTB MMIO Space, which may hang the system. To workaround - * this use the second memory window to access the interrupt and - * scratch pad registers on the remote system. - */ - if (ndev->wa_flags & WA_SNB_ERR) { - if (!ndev->mw[ndev->limits.max_mw - 1].bar_sz) - return -EINVAL; - - ndev->limits.max_db_bits = SNB_MAX_DB_BITS; - ndev->reg_ofs.spad_write = - ndev->mw[ndev->limits.max_mw - 1].vbase + - SNB_SPAD_OFFSET; - ndev->reg_ofs.rdb = - ndev->mw[ndev->limits.max_mw - 1].vbase + - SNB_PDOORBELL_OFFSET; - - /* Set the Limit register to 4k, the minimum size, to - * prevent an illegal access - */ - writeq(ndev->mw[1].bar_sz + 0x1000, ndev->reg_base + - SNB_PBAR4LMT_OFFSET); - /* HW errata on the Limit registers. They can only be - * written when the base register is 4GB aligned and - * < 32bit. This should already be the case based on - * the driver defaults, but write the Limit registers - * first just in case. - */ - - ndev->limits.max_mw = SNB_ERRATA_MAX_MW; - } else { - /* HW Errata on bit 14 of b2bdoorbell register. Writes - * will not be mirrored to the remote system. Shrink - * the number of bits by one, since bit 14 is the last - * bit. - */ - ndev->limits.max_db_bits = SNB_MAX_DB_BITS - 1; - ndev->reg_ofs.spad_write = ndev->reg_base + - SNB_B2B_SPAD_OFFSET; - ndev->reg_ofs.rdb = ndev->reg_base + - SNB_B2B_DOORBELL_OFFSET; - - /* Disable the Limit register, just incase it is set to - * something silly. A 64bit write should handle it - * regardless of whether it has a split BAR or not. - */ - writeq(0, ndev->reg_base + SNB_PBAR4LMT_OFFSET); - /* HW errata on the Limit registers. They can only be - * written when the base register is 4GB aligned and - * < 32bit. This should already be the case based on - * the driver defaults, but write the Limit registers - * first just in case. - */ - if (ndev->split_bar) - ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW; - else - ndev->limits.max_mw = SNB_MAX_MW; - } +static int intel_ntb_mw_get_range(struct ntb_dev *ntb, int idx, + phys_addr_t *base, + resource_size_t *size, + resource_size_t *align, + resource_size_t *align_size) +{ + struct intel_ntb_dev *ndev = ntb_ndev(ntb); + int bar; - /* The Xeon errata workaround requires setting SBAR Base - * addresses to known values, so that the PBAR XLAT can be - * pointed at SBAR0 of the remote system. - */ - if (ndev->dev_type == NTB_DEV_USD) { - writeq(SNB_MBAR23_DSD_ADDR, ndev->reg_base + - SNB_PBAR2XLAT_OFFSET); - if (ndev->wa_flags & WA_SNB_ERR) - writeq(SNB_MBAR01_DSD_ADDR, ndev->reg_base + - SNB_PBAR4XLAT_OFFSET); - else { - if (ndev->split_bar) { - writel(SNB_MBAR4_DSD_ADDR, - ndev->reg_base + - SNB_PBAR4XLAT_OFFSET); - writel(SNB_MBAR5_DSD_ADDR, - ndev->reg_base + - SNB_PBAR5XLAT_OFFSET); - } else - writeq(SNB_MBAR4_DSD_ADDR, - ndev->reg_base + - SNB_PBAR4XLAT_OFFSET); - - /* B2B_XLAT_OFFSET is a 64bit register, but can - * only take 32bit writes - */ - writel(SNB_MBAR01_DSD_ADDR & 0xffffffff, - ndev->reg_base + SNB_B2B_XLAT_OFFSETL); - writel(SNB_MBAR01_DSD_ADDR >> 32, - ndev->reg_base + SNB_B2B_XLAT_OFFSETU); - } - - writeq(SNB_MBAR01_USD_ADDR, ndev->reg_base + - SNB_SBAR0BASE_OFFSET); - writeq(SNB_MBAR23_USD_ADDR, ndev->reg_base + - SNB_SBAR2BASE_OFFSET); - if (ndev->split_bar) { - writel(SNB_MBAR4_USD_ADDR, ndev->reg_base + - SNB_SBAR4BASE_OFFSET); - writel(SNB_MBAR5_USD_ADDR, ndev->reg_base + - SNB_SBAR5BASE_OFFSET); - } else - writeq(SNB_MBAR4_USD_ADDR, ndev->reg_base + - SNB_SBAR4BASE_OFFSET); - } else { - writeq(SNB_MBAR23_USD_ADDR, ndev->reg_base + - SNB_PBAR2XLAT_OFFSET); - if (ndev->wa_flags & WA_SNB_ERR) - writeq(SNB_MBAR01_USD_ADDR, ndev->reg_base + - SNB_PBAR4XLAT_OFFSET); - else { - if (ndev->split_bar) { - writel(SNB_MBAR4_USD_ADDR, - ndev->reg_base + - SNB_PBAR4XLAT_OFFSET); - writel(SNB_MBAR5_USD_ADDR, - ndev->reg_base + - SNB_PBAR5XLAT_OFFSET); - } else - writeq(SNB_MBAR4_USD_ADDR, - ndev->reg_base + - SNB_PBAR4XLAT_OFFSET); - - /* - * B2B_XLAT_OFFSET is a 64bit register, but can - * only take 32bit writes - */ - writel(SNB_MBAR01_USD_ADDR & 0xffffffff, - ndev->reg_base + SNB_B2B_XLAT_OFFSETL); - writel(SNB_MBAR01_USD_ADDR >> 32, - ndev->reg_base + SNB_B2B_XLAT_OFFSETU); - } - writeq(SNB_MBAR01_DSD_ADDR, ndev->reg_base + - SNB_SBAR0BASE_OFFSET); - writeq(SNB_MBAR23_DSD_ADDR, ndev->reg_base + - SNB_SBAR2BASE_OFFSET); - if (ndev->split_bar) { - writel(SNB_MBAR4_DSD_ADDR, ndev->reg_base + - SNB_SBAR4BASE_OFFSET); - writel(SNB_MBAR5_DSD_ADDR, ndev->reg_base + - SNB_SBAR5BASE_OFFSET); - } else - writeq(SNB_MBAR4_DSD_ADDR, ndev->reg_base + - SNB_SBAR4BASE_OFFSET); + if (idx >= ndev->b2b_idx && !ndev->b2b_off) + idx += 1; - } - break; - case NTB_CONN_RP: - if (ndev->wa_flags & WA_SNB_ERR) { - dev_err(&ndev->pdev->dev, - "NTB-RP disabled due to hardware errata.\n"); - return -EINVAL; - } + bar = ndev_mw_to_bar(ndev, idx); + if (bar < 0) + return bar; - /* Scratch pads need to have exclusive access from the primary - * or secondary side. Halve the num spads so that each side can - * have an equal amount. - */ - ndev->limits.max_spads = SNB_MAX_COMPAT_SPADS / 2; - ndev->limits.max_db_bits = SNB_MAX_DB_BITS; - /* Note: The SDOORBELL is the cause of the errata. You REALLY - * don't want to touch it. - */ - ndev->reg_ofs.rdb = ndev->reg_base + SNB_SDOORBELL_OFFSET; - ndev->reg_ofs.ldb = ndev->reg_base + SNB_PDOORBELL_OFFSET; - ndev->reg_ofs.ldb_mask = ndev->reg_base + SNB_PDBMSK_OFFSET; - /* Offset the start of the spads to correspond to whether it is - * primary or secondary - */ - ndev->reg_ofs.spad_write = ndev->reg_base + SNB_SPAD_OFFSET + - ndev->limits.max_spads * 4; - ndev->reg_ofs.spad_read = ndev->reg_base + SNB_SPAD_OFFSET; - ndev->reg_ofs.bar2_xlat = ndev->reg_base + SNB_SBAR2XLAT_OFFSET; - ndev->reg_ofs.bar4_xlat = ndev->reg_base + SNB_SBAR4XLAT_OFFSET; - if (ndev->split_bar) { - ndev->reg_ofs.bar5_xlat = - ndev->reg_base + SNB_SBAR5XLAT_OFFSET; - ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW; - } else - ndev->limits.max_mw = SNB_MAX_MW; - break; - case NTB_CONN_TRANSPARENT: - if (ndev->wa_flags & WA_SNB_ERR) { - dev_err(&ndev->pdev->dev, - "NTB-TRANSPARENT disabled due to hardware errata.\n"); - return -EINVAL; - } + if (base) + *base = pci_resource_start(ndev->ntb.pdev, bar) + + (idx == ndev->b2b_idx ? ndev->b2b_off : 0); - /* Scratch pads need to have exclusive access from the primary - * or secondary side. Halve the num spads so that each side can - * have an equal amount. - */ - ndev->limits.max_spads = SNB_MAX_COMPAT_SPADS / 2; - ndev->limits.max_db_bits = SNB_MAX_DB_BITS; - ndev->reg_ofs.rdb = ndev->reg_base + SNB_PDOORBELL_OFFSET; - ndev->reg_ofs.ldb = ndev->reg_base + SNB_SDOORBELL_OFFSET; - ndev->reg_ofs.ldb_mask = ndev->reg_base + SNB_SDBMSK_OFFSET; - ndev->reg_ofs.spad_write = ndev->reg_base + SNB_SPAD_OFFSET; - /* Offset the start of the spads to correspond to whether it is - * primary or secondary - */ - ndev->reg_ofs.spad_read = ndev->reg_base + SNB_SPAD_OFFSET + - ndev->limits.max_spads * 4; - ndev->reg_ofs.bar2_xlat = ndev->reg_base + SNB_PBAR2XLAT_OFFSET; - ndev->reg_ofs.bar4_xlat = ndev->reg_base + SNB_PBAR4XLAT_OFFSET; - - if (ndev->split_bar) { - ndev->reg_ofs.bar5_xlat = - ndev->reg_base + SNB_PBAR5XLAT_OFFSET; - ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW; - } else - ndev->limits.max_mw = SNB_MAX_MW; - break; - default: - /* - * we should never hit this. the detect function should've - * take cared of everything. - */ - return -EINVAL; - } + if (size) + *size = pci_resource_len(ndev->ntb.pdev, bar) - + (idx == ndev->b2b_idx ? ndev->b2b_off : 0); - ndev->reg_ofs.lnk_cntl = ndev->reg_base + SNB_NTBCNTL_OFFSET; - ndev->reg_ofs.lnk_stat = ndev->reg_base + SNB_SLINK_STATUS_OFFSET; - ndev->reg_ofs.spci_cmd = ndev->reg_base + SNB_PCICMD_OFFSET; + if (align) + *align = pci_resource_len(ndev->ntb.pdev, bar); - ndev->limits.msix_cnt = SNB_MSIX_CNT; - ndev->bits_per_vector = SNB_DB_BITS_PER_VEC; + if (align_size) + *align_size = 1; return 0; } -static int ntb_bwd_setup(struct ntb_device *ndev) +static int intel_ntb_mw_set_trans(struct ntb_dev *ntb, int idx, + dma_addr_t addr, resource_size_t size) { - int rc; - u32 val; + struct intel_ntb_dev *ndev = ntb_ndev(ntb); + unsigned long base_reg, xlat_reg, limit_reg; + resource_size_t bar_size, mw_size; + void __iomem *mmio; + u64 base, limit, reg_val; + int bar; - ndev->hw_type = BWD_HW; + if (idx >= ndev->b2b_idx && !ndev->b2b_off) + idx += 1; - rc = pci_read_config_dword(ndev->pdev, NTB_PPD_OFFSET, &val); - if (rc) - return rc; + bar = ndev_mw_to_bar(ndev, idx); + if (bar < 0) + return bar; - switch ((val & BWD_PPD_CONN_TYPE) >> 8) { - case NTB_CONN_B2B: - ndev->conn_type = NTB_CONN_B2B; - break; - case NTB_CONN_RP: - default: - dev_err(&ndev->pdev->dev, "Unsupported NTB configuration\n"); + bar_size = pci_resource_len(ndev->ntb.pdev, bar); + + if (idx == ndev->b2b_idx) + mw_size = bar_size - ndev->b2b_off; + else + mw_size = bar_size; + + /* hardware requires that addr is aligned to bar size */ + if (addr & (bar_size - 1)) return -EINVAL; + + /* make sure the range fits in the usable mw size */ + if (size > mw_size) + return -EINVAL; + + mmio = ndev->self_mmio; + base_reg = bar0_off(ndev->xlat_reg->bar0_base, bar); + xlat_reg = bar2_off(ndev->xlat_reg->bar2_xlat, bar); + limit_reg = bar2_off(ndev->xlat_reg->bar2_limit, bar); + + if (bar < 4 || !ndev->bar4_split) { + base = ioread64(mmio + base_reg); + + /* Set the limit if supported, if size is not mw_size */ + if (limit_reg && size != mw_size) + limit = base + size; + else + limit = 0; + + /* set and verify setting the translation address */ + iowrite64(addr, mmio + xlat_reg); + reg_val = ioread64(mmio + xlat_reg); + if (reg_val != addr) { + iowrite64(0, mmio + xlat_reg); + return -EIO; + } + + /* set and verify setting the limit */ + iowrite64(limit, mmio + limit_reg); + reg_val = ioread64(mmio + limit_reg); + if (reg_val != limit) { + iowrite64(base, mmio + limit_reg); + iowrite64(0, mmio + xlat_reg); + return -EIO; + } + } else { + /* split bar addr range must all be 32 bit */ + if (addr & (~0ull << 32)) + return -EINVAL; + if ((addr + size) & (~0ull << 32)) + return -EINVAL; + + base = ioread32(mmio + base_reg); + + /* Set the limit if supported, if size is not mw_size */ + if (limit_reg && size != mw_size) + limit = base + size; + else + limit = 0; + + /* set and verify setting the translation address */ + iowrite32(addr, mmio + xlat_reg); + reg_val = ioread32(mmio + xlat_reg); + if (reg_val != addr) { + iowrite32(0, mmio + xlat_reg); + return -EIO; + } + + /* set and verify setting the limit */ + iowrite32(limit, mmio + limit_reg); + reg_val = ioread32(mmio + limit_reg); + if (reg_val != limit) { + iowrite32(base, mmio + limit_reg); + iowrite32(0, mmio + xlat_reg); + return -EIO; + } } - if (val & BWD_PPD_DEV_TYPE) - ndev->dev_type = NTB_DEV_DSD; - else - ndev->dev_type = NTB_DEV_USD; + return 0; +} - /* Initiate PCI-E link training */ - rc = pci_write_config_dword(ndev->pdev, NTB_PPD_OFFSET, - val | BWD_PPD_INIT_LINK); - if (rc) - return rc; +static int intel_ntb_link_is_up(struct ntb_dev *ntb, + enum ntb_speed *speed, + enum ntb_width *width) +{ + struct intel_ntb_dev *ndev = ntb_ndev(ntb); - ndev->reg_ofs.ldb = ndev->reg_base + BWD_PDOORBELL_OFFSET; - ndev->reg_ofs.ldb_mask = ndev->reg_base + BWD_PDBMSK_OFFSET; - ndev->reg_ofs.rdb = ndev->reg_base + BWD_B2B_DOORBELL_OFFSET; - ndev->reg_ofs.bar2_xlat = ndev->reg_base + BWD_SBAR2XLAT_OFFSET; - ndev->reg_ofs.bar4_xlat = ndev->reg_base + BWD_SBAR4XLAT_OFFSET; - ndev->reg_ofs.lnk_cntl = ndev->reg_base + BWD_NTBCNTL_OFFSET; - ndev->reg_ofs.lnk_stat = ndev->reg_base + BWD_LINK_STATUS_OFFSET; - ndev->reg_ofs.spad_read = ndev->reg_base + BWD_SPAD_OFFSET; - ndev->reg_ofs.spad_write = ndev->reg_base + BWD_B2B_SPAD_OFFSET; - ndev->reg_ofs.spci_cmd = ndev->reg_base + BWD_PCICMD_OFFSET; - ndev->limits.max_mw = BWD_MAX_MW; - ndev->limits.max_spads = BWD_MAX_SPADS; - ndev->limits.max_db_bits = BWD_MAX_DB_BITS; - ndev->limits.msix_cnt = BWD_MSIX_CNT; - ndev->bits_per_vector = BWD_DB_BITS_PER_VEC; - - /* Since bwd doesn't have a link interrupt, setup a poll timer */ - INIT_DELAYED_WORK(&ndev->hb_timer, bwd_link_poll); - INIT_DELAYED_WORK(&ndev->lr_timer, bwd_link_recovery); - schedule_delayed_work(&ndev->hb_timer, NTB_HB_TIMEOUT); + if (ndev->reg->link_is_up(ndev)) { + if (speed) + *speed = NTB_LNK_STA_SPEED(ndev->lnk_sta); + if (width) + *width = NTB_LNK_STA_WIDTH(ndev->lnk_sta); + return 1; + } else { + /* TODO MAYBE: is it possible to observe the link speed and + * width while link is training? */ + if (speed) + *speed = NTB_SPEED_NONE; + if (width) + *width = NTB_WIDTH_NONE; + return 0; + } +} + +static int intel_ntb_link_enable(struct ntb_dev *ntb, + enum ntb_speed max_speed, + enum ntb_width max_width) +{ + struct intel_ntb_dev *ndev; + u32 ntb_ctl; + + ndev = container_of(ntb, struct intel_ntb_dev, ntb); + + if (ndev->ntb.topo == NTB_TOPO_SEC) + return -EINVAL; + + dev_dbg(ndev_dev(ndev), + "Enabling link with max_speed %d max_width %d\n", + max_speed, max_width); + if (max_speed != NTB_SPEED_AUTO) + dev_dbg(ndev_dev(ndev), "ignoring max_speed %d\n", max_speed); + if (max_width != NTB_WIDTH_AUTO) + dev_dbg(ndev_dev(ndev), "ignoring max_width %d\n", max_width); + + ntb_ctl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl); + ntb_ctl &= ~(NTB_CTL_DISABLE | NTB_CTL_CFG_LOCK); + ntb_ctl |= NTB_CTL_P2S_BAR2_SNOOP | NTB_CTL_S2P_BAR2_SNOOP; + ntb_ctl |= NTB_CTL_P2S_BAR4_SNOOP | NTB_CTL_S2P_BAR4_SNOOP; + if (ndev->bar4_split) + ntb_ctl |= NTB_CTL_P2S_BAR5_SNOOP | NTB_CTL_S2P_BAR5_SNOOP; + iowrite32(ntb_ctl, ndev->self_mmio + ndev->reg->ntb_ctl); return 0; } -static int ntb_device_setup(struct ntb_device *ndev) +static int intel_ntb_link_disable(struct ntb_dev *ntb) { - int rc; + struct intel_ntb_dev *ndev; + u32 ntb_cntl; - if (is_ntb_xeon(ndev)) - rc = ntb_xeon_setup(ndev); - else if (is_ntb_atom(ndev)) - rc = ntb_bwd_setup(ndev); - else - rc = -ENODEV; + ndev = container_of(ntb, struct intel_ntb_dev, ntb); - if (rc) - return rc; + if (ndev->ntb.topo == NTB_TOPO_SEC) + return -EINVAL; - if (ndev->conn_type == NTB_CONN_B2B) - /* Enable Bus Master and Memory Space on the secondary side */ - writew(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER, - ndev->reg_ofs.spci_cmd); + dev_dbg(ndev_dev(ndev), "Disabling link\n"); + + /* Bring NTB link down */ + ntb_cntl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl); + ntb_cntl &= ~(NTB_CTL_P2S_BAR2_SNOOP | NTB_CTL_S2P_BAR2_SNOOP); + ntb_cntl &= ~(NTB_CTL_P2S_BAR4_SNOOP | NTB_CTL_S2P_BAR4_SNOOP); + if (ndev->bar4_split) + ntb_cntl &= ~(NTB_CTL_P2S_BAR5_SNOOP | NTB_CTL_S2P_BAR5_SNOOP); + ntb_cntl |= NTB_CTL_DISABLE | NTB_CTL_CFG_LOCK; + iowrite32(ntb_cntl, ndev->self_mmio + ndev->reg->ntb_ctl); return 0; } -static void ntb_device_free(struct ntb_device *ndev) +static int intel_ntb_db_is_unsafe(struct ntb_dev *ntb) { - if (is_ntb_atom(ndev)) { - cancel_delayed_work_sync(&ndev->hb_timer); - cancel_delayed_work_sync(&ndev->lr_timer); - } + return ndev_ignore_unsafe(ntb_ndev(ntb), NTB_UNSAFE_DB); } -static irqreturn_t bwd_callback_msix_irq(int irq, void *data) +static u64 intel_ntb_db_valid_mask(struct ntb_dev *ntb) { - struct ntb_db_cb *db_cb = data; - struct ntb_device *ndev = db_cb->ndev; - unsigned long mask; + return ntb_ndev(ntb)->db_valid_mask; +} - dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for DB %d\n", irq, - db_cb->db_num); +static int intel_ntb_db_vector_count(struct ntb_dev *ntb) +{ + struct intel_ntb_dev *ndev; - mask = readw(ndev->reg_ofs.ldb_mask); - set_bit(db_cb->db_num * ndev->bits_per_vector, &mask); - writew(mask, ndev->reg_ofs.ldb_mask); + ndev = container_of(ntb, struct intel_ntb_dev, ntb); - tasklet_schedule(&db_cb->irq_work); + return ndev->db_vec_count; +} - /* No need to check for the specific HB irq, any interrupt means - * we're connected. - */ - ndev->last_ts = jiffies; +static u64 intel_ntb_db_vector_mask(struct ntb_dev *ntb, int db_vector) +{ + struct intel_ntb_dev *ndev = ntb_ndev(ntb); - writeq((u64) 1 << db_cb->db_num, ndev->reg_ofs.ldb); + if (db_vector < 0 || db_vector > ndev->db_vec_count) + return 0; - return IRQ_HANDLED; + return ndev->db_valid_mask & ndev_vec_mask(ndev, db_vector); } -static irqreturn_t xeon_callback_msix_irq(int irq, void *data) +static u64 intel_ntb_db_read(struct ntb_dev *ntb) { - struct ntb_db_cb *db_cb = data; - struct ntb_device *ndev = db_cb->ndev; - unsigned long mask; + struct intel_ntb_dev *ndev = ntb_ndev(ntb); - dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for DB %d\n", irq, - db_cb->db_num); + return ndev_db_read(ndev, + ndev->self_mmio + + ndev->self_reg->db_bell); +} - mask = readw(ndev->reg_ofs.ldb_mask); - set_bit(db_cb->db_num * ndev->bits_per_vector, &mask); - writew(mask, ndev->reg_ofs.ldb_mask); +static int intel_ntb_db_clear(struct ntb_dev *ntb, u64 db_bits) +{ + struct intel_ntb_dev *ndev = ntb_ndev(ntb); - tasklet_schedule(&db_cb->irq_work); + return ndev_db_write(ndev, db_bits, + ndev->self_mmio + + ndev->self_reg->db_bell); +} - /* On Sandybridge, there are 16 bits in the interrupt register - * but only 4 vectors. So, 5 bits are assigned to the first 3 - * vectors, with the 4th having a single bit for link - * interrupts. - */ - writew(((1 << ndev->bits_per_vector) - 1) << - (db_cb->db_num * ndev->bits_per_vector), ndev->reg_ofs.ldb); +static int intel_ntb_db_set_mask(struct ntb_dev *ntb, u64 db_bits) +{ + struct intel_ntb_dev *ndev = ntb_ndev(ntb); - return IRQ_HANDLED; + return ndev_db_set_mask(ndev, db_bits, + ndev->self_mmio + + ndev->self_reg->db_mask); } -/* Since we do not have a HW doorbell in BWD, this is only used in JF/JT */ -static irqreturn_t xeon_event_msix_irq(int irq, void *dev) +static int intel_ntb_db_clear_mask(struct ntb_dev *ntb, u64 db_bits) { - struct ntb_device *ndev = dev; - int rc; - - dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for Events\n", irq); + struct intel_ntb_dev *ndev = ntb_ndev(ntb); - rc = ntb_link_status(ndev); - if (rc) - dev_err(&ndev->pdev->dev, "Error determining link status\n"); + return ndev_db_clear_mask(ndev, db_bits, + ndev->self_mmio + + ndev->self_reg->db_mask); +} - /* bit 15 is always the link bit */ - writew(1 << SNB_LINK_DB, ndev->reg_ofs.ldb); +static int intel_ntb_peer_db_addr(struct ntb_dev *ntb, + phys_addr_t *db_addr, + resource_size_t *db_size) +{ + struct intel_ntb_dev *ndev = ntb_ndev(ntb); - return IRQ_HANDLED; + return ndev_db_addr(ndev, db_addr, db_size, ndev->peer_addr, + ndev->peer_reg->db_bell); } -static irqreturn_t ntb_interrupt(int irq, void *dev) +static int intel_ntb_peer_db_set(struct ntb_dev *ntb, u64 db_bits) { - struct ntb_device *ndev = dev; - unsigned int i = 0; + struct intel_ntb_dev *ndev = ntb_ndev(ntb); - if (is_ntb_atom(ndev)) { - u64 ldb = readq(ndev->reg_ofs.ldb); + return ndev_db_write(ndev, db_bits, + ndev->peer_mmio + + ndev->peer_reg->db_bell); +} - dev_dbg(&ndev->pdev->dev, "irq %d - ldb = %Lx\n", irq, ldb); +static int intel_ntb_spad_is_unsafe(struct ntb_dev *ntb) +{ + return ndev_ignore_unsafe(ntb_ndev(ntb), NTB_UNSAFE_SPAD); +} - while (ldb) { - i = __ffs(ldb); - ldb &= ldb - 1; - bwd_callback_msix_irq(irq, &ndev->db_cb[i]); - } - } else { - u16 ldb = readw(ndev->reg_ofs.ldb); +static int intel_ntb_spad_count(struct ntb_dev *ntb) +{ + struct intel_ntb_dev *ndev; - dev_dbg(&ndev->pdev->dev, "irq %d - ldb = %x\n", irq, ldb); + ndev = container_of(ntb, struct intel_ntb_dev, ntb); - if (ldb & SNB_DB_HW_LINK) { - xeon_event_msix_irq(irq, dev); - ldb &= ~SNB_DB_HW_LINK; - } + return ndev->spad_count; +} - while (ldb) { - i = __ffs(ldb); - ldb &= ldb - 1; - xeon_callback_msix_irq(irq, &ndev->db_cb[i]); - } - } +static u32 intel_ntb_spad_read(struct ntb_dev *ntb, int idx) +{ + struct intel_ntb_dev *ndev = ntb_ndev(ntb); - return IRQ_HANDLED; + return ndev_spad_read(ndev, idx, + ndev->self_mmio + + ndev->self_reg->spad); } -static int ntb_setup_snb_msix(struct ntb_device *ndev, int msix_entries) +static int intel_ntb_spad_write(struct ntb_dev *ntb, + int idx, u32 val) { - struct pci_dev *pdev = ndev->pdev; - struct msix_entry *msix; - int rc, i; + struct intel_ntb_dev *ndev = ntb_ndev(ntb); - if (msix_entries < ndev->limits.msix_cnt) - return -ENOSPC; + return ndev_spad_write(ndev, idx, val, + ndev->self_mmio + + ndev->self_reg->spad); +} - rc = pci_enable_msix_exact(pdev, ndev->msix_entries, msix_entries); - if (rc < 0) - return rc; +static int intel_ntb_peer_spad_addr(struct ntb_dev *ntb, int idx, + phys_addr_t *spad_addr) +{ + struct intel_ntb_dev *ndev = ntb_ndev(ntb); - for (i = 0; i < msix_entries; i++) { - msix = &ndev->msix_entries[i]; - WARN_ON(!msix->vector); + return ndev_spad_addr(ndev, idx, spad_addr, ndev->peer_addr, + ndev->peer_reg->spad); +} - if (i == msix_entries - 1) { - rc = request_irq(msix->vector, - xeon_event_msix_irq, 0, - "ntb-event-msix", ndev); - if (rc) - goto err; - } else { - rc = request_irq(msix->vector, - xeon_callback_msix_irq, 0, - "ntb-callback-msix", - &ndev->db_cb[i]); - if (rc) - goto err; - } - } +static u32 intel_ntb_peer_spad_read(struct ntb_dev *ntb, int idx) +{ + struct intel_ntb_dev *ndev = ntb_ndev(ntb); - ndev->num_msix = msix_entries; - ndev->max_cbs = msix_entries - 1; + return ndev_spad_read(ndev, idx, + ndev->peer_mmio + + ndev->peer_reg->spad); +} - return 0; +static int intel_ntb_peer_spad_write(struct ntb_dev *ntb, + int idx, u32 val) +{ + struct intel_ntb_dev *ndev = ntb_ndev(ntb); -err: - while (--i >= 0) { - /* Code never reaches here for entry nr 'ndev->num_msix - 1' */ - msix = &ndev->msix_entries[i]; - free_irq(msix->vector, &ndev->db_cb[i]); - } + return ndev_spad_write(ndev, idx, val, + ndev->peer_mmio + + ndev->peer_reg->spad); +} - pci_disable_msix(pdev); - ndev->num_msix = 0; +/* BWD */ - return rc; +static u64 bwd_db_ioread(void __iomem *mmio) +{ + return ioread64(mmio); +} + +static void bwd_db_iowrite(u64 bits, void __iomem *mmio) +{ + iowrite64(bits, mmio); } -static int ntb_setup_bwd_msix(struct ntb_device *ndev, int msix_entries) +static int bwd_poll_link(struct intel_ntb_dev *ndev) { - struct pci_dev *pdev = ndev->pdev; - struct msix_entry *msix; - int rc, i; + u32 ntb_ctl; - msix_entries = pci_enable_msix_range(pdev, ndev->msix_entries, - 1, msix_entries); - if (msix_entries < 0) - return msix_entries; + ntb_ctl = ioread32(ndev->self_mmio + BWD_NTBCNTL_OFFSET); - for (i = 0; i < msix_entries; i++) { - msix = &ndev->msix_entries[i]; - WARN_ON(!msix->vector); + if (ntb_ctl == ndev->ntb_ctl) + return 0; - rc = request_irq(msix->vector, bwd_callback_msix_irq, 0, - "ntb-callback-msix", &ndev->db_cb[i]); - if (rc) - goto err; - } + ndev->ntb_ctl = ntb_ctl; - ndev->num_msix = msix_entries; - ndev->max_cbs = msix_entries; + ndev->lnk_sta = ioread32(ndev->self_mmio + BWD_LINK_STATUS_OFFSET); - return 0; + return 1; +} -err: - while (--i >= 0) - free_irq(msix->vector, &ndev->db_cb[i]); +static int bwd_link_is_up(struct intel_ntb_dev *ndev) +{ + return BWD_NTB_CTL_ACTIVE(ndev->ntb_ctl); +} - pci_disable_msix(pdev); - ndev->num_msix = 0; +static int bwd_link_is_err(struct intel_ntb_dev *ndev) +{ + if (ioread32(ndev->self_mmio + BWD_LTSSMSTATEJMP_OFFSET) + & BWD_LTSSMSTATEJMP_FORCEDETECT) + return 1; - return rc; + if (ioread32(ndev->self_mmio + BWD_IBSTERRRCRVSTS0_OFFSET) + & BWD_IBIST_ERR_OFLOW) + return 1; + + return 0; } -static int ntb_setup_msix(struct ntb_device *ndev) +static inline enum ntb_topo bwd_ppd_topo(struct intel_ntb_dev *ndev, u32 ppd) { - struct pci_dev *pdev = ndev->pdev; - int msix_entries; - int rc, i; + switch (ppd & BWD_PPD_TOPO_MASK) { + case BWD_PPD_TOPO_B2B_USD: + dev_dbg(ndev_dev(ndev), "PPD %d B2B USD\n", ppd); + return NTB_TOPO_B2B_USD; + + case BWD_PPD_TOPO_B2B_DSD: + dev_dbg(ndev_dev(ndev), "PPD %d B2B DSD\n", ppd); + return NTB_TOPO_B2B_DSD; + + case BWD_PPD_TOPO_PRI_USD: + case BWD_PPD_TOPO_PRI_DSD: /* accept bogus PRI_DSD */ + case BWD_PPD_TOPO_SEC_USD: + case BWD_PPD_TOPO_SEC_DSD: /* accept bogus SEC_DSD */ + dev_dbg(ndev_dev(ndev), "PPD %d non B2B disabled\n", ppd); + return NTB_TOPO_NONE; + } - msix_entries = pci_msix_vec_count(pdev); - if (msix_entries < 0) { - rc = msix_entries; - goto err; - } else if (msix_entries > ndev->limits.msix_cnt) { - rc = -EINVAL; - goto err; + dev_dbg(ndev_dev(ndev), "PPD %d invalid\n", ppd); + return NTB_TOPO_NONE; +} + +static void bwd_link_hb(struct work_struct *work) +{ + struct intel_ntb_dev *ndev = hb_ndev(work); + unsigned long poll_ts; + void __iomem *mmio; + u32 status32; + + poll_ts = ndev->last_ts + BWD_LINK_HB_TIMEOUT; + + /* Delay polling the link status if an interrupt was received, + * unless the cached link status says the link is down. + */ + if (time_after(poll_ts, jiffies) && bwd_link_is_up(ndev)) { + schedule_delayed_work(&ndev->hb_timer, poll_ts - jiffies); + return; } - ndev->msix_entries = kmalloc(sizeof(struct msix_entry) * msix_entries, - GFP_KERNEL); - if (!ndev->msix_entries) { - rc = -ENOMEM; - goto err; + if (bwd_poll_link(ndev)) + ntb_link_event(&ndev->ntb); + + if (bwd_link_is_up(ndev) || !bwd_link_is_err(ndev)) { + schedule_delayed_work(&ndev->hb_timer, BWD_LINK_HB_TIMEOUT); + return; } - for (i = 0; i < msix_entries; i++) - ndev->msix_entries[i].entry = i; + /* Link is down with error: recover the link! */ - if (is_ntb_atom(ndev)) - rc = ntb_setup_bwd_msix(ndev, msix_entries); - else - rc = ntb_setup_snb_msix(ndev, msix_entries); - if (rc) - goto err1; + mmio = ndev->self_mmio; - return 0; + /* Driver resets the NTB ModPhy lanes - magic! */ + iowrite8(0xe0, mmio + BWD_MODPHY_PCSREG6); + iowrite8(0x40, mmio + BWD_MODPHY_PCSREG4); + iowrite8(0x60, mmio + BWD_MODPHY_PCSREG4); + iowrite8(0x60, mmio + BWD_MODPHY_PCSREG6); -err1: - kfree(ndev->msix_entries); -err: - dev_err(&pdev->dev, "Error allocating MSI-X interrupt\n"); - return rc; + /* Driver waits 100ms to allow the NTB ModPhy to settle */ + msleep(100); + + /* Clear AER Errors, write to clear */ + status32 = ioread32(mmio + BWD_ERRCORSTS_OFFSET); + dev_dbg(ndev_dev(ndev), "ERRCORSTS = %x\n", status32); + status32 &= PCI_ERR_COR_REP_ROLL; + iowrite32(status32, mmio + BWD_ERRCORSTS_OFFSET); + + /* Clear unexpected electrical idle event in LTSSM, write to clear */ + status32 = ioread32(mmio + BWD_LTSSMERRSTS0_OFFSET); + dev_dbg(ndev_dev(ndev), "LTSSMERRSTS0 = %x\n", status32); + status32 |= BWD_LTSSMERRSTS0_UNEXPECTEDEI; + iowrite32(status32, mmio + BWD_LTSSMERRSTS0_OFFSET); + + /* Clear DeSkew Buffer error, write to clear */ + status32 = ioread32(mmio + BWD_DESKEWSTS_OFFSET); + dev_dbg(ndev_dev(ndev), "DESKEWSTS = %x\n", status32); + status32 |= BWD_DESKEWSTS_DBERR; + iowrite32(status32, mmio + BWD_DESKEWSTS_OFFSET); + + status32 = ioread32(mmio + BWD_IBSTERRRCRVSTS0_OFFSET); + dev_dbg(ndev_dev(ndev), "IBSTERRRCRVSTS0 = %x\n", status32); + status32 &= BWD_IBIST_ERR_OFLOW; + iowrite32(status32, mmio + BWD_IBSTERRRCRVSTS0_OFFSET); + + /* Releases the NTB state machine to allow the link to retrain */ + status32 = ioread32(mmio + BWD_LTSSMSTATEJMP_OFFSET); + dev_dbg(ndev_dev(ndev), "LTSSMSTATEJMP = %x\n", status32); + status32 &= ~BWD_LTSSMSTATEJMP_FORCEDETECT; + iowrite32(status32, mmio + BWD_LTSSMSTATEJMP_OFFSET); + + /* There is a potential race between the 2 NTB devices recovering at the + * same time. If the times are the same, the link will not recover and + * the driver will be stuck in this loop forever. Add a random interval + * to the recovery time to prevent this race. + */ + schedule_delayed_work(&ndev->hb_timer, BWD_LINK_RECOVERY_TIME + + prandom_u32() % BWD_LINK_RECOVERY_TIME); } -static int ntb_setup_msi(struct ntb_device *ndev) +static int bwd_init_isr(struct intel_ntb_dev *ndev) { - struct pci_dev *pdev = ndev->pdev; int rc; - rc = pci_enable_msi(pdev); + rc = ndev_init_isr(ndev, 1, BWD_DB_MSIX_VECTOR_COUNT, + BWD_DB_MSIX_VECTOR_SHIFT, BWD_DB_TOTAL_SHIFT); if (rc) return rc; - rc = request_irq(pdev->irq, ntb_interrupt, 0, "ntb-msi", ndev); - if (rc) { - pci_disable_msi(pdev); - dev_err(&pdev->dev, "Error allocating MSI interrupt\n"); - return rc; - } + /* BWD doesn't have link status interrupt, poll on that platform */ + ndev->last_ts = jiffies; + INIT_DELAYED_WORK(&ndev->hb_timer, bwd_link_hb); + schedule_delayed_work(&ndev->hb_timer, BWD_LINK_HB_TIMEOUT); return 0; } -static int ntb_setup_intx(struct ntb_device *ndev) +static void bwd_deinit_isr(struct intel_ntb_dev *ndev) { - struct pci_dev *pdev = ndev->pdev; - int rc; + cancel_delayed_work_sync(&ndev->hb_timer); + ndev_deinit_isr(ndev); +} - /* Verify intx is enabled */ - pci_intx(pdev, 1); +static int bwd_init_ntb(struct intel_ntb_dev *ndev) +{ + ndev->mw_count = BWD_MW_COUNT; + ndev->spad_count = BWD_SPAD_COUNT; + ndev->db_count = BWD_DB_COUNT; - rc = request_irq(pdev->irq, ntb_interrupt, IRQF_SHARED, "ntb-intx", - ndev); - if (rc) - return rc; + switch (ndev->ntb.topo) { + case NTB_TOPO_B2B_USD: + case NTB_TOPO_B2B_DSD: + ndev->self_reg = &bwd_pri_reg; + ndev->peer_reg = &bwd_b2b_reg; + ndev->xlat_reg = &bwd_sec_xlat; + + /* Enable Bus Master and Memory Space on the secondary side */ + iowrite16(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER, + ndev->self_mmio + BWD_SPCICMD_OFFSET); + + break; + + default: + return -EINVAL; + } + + ndev->db_valid_mask = BIT_ULL(ndev->db_count) - 1; return 0; } -static int ntb_setup_interrupts(struct ntb_device *ndev) +static int bwd_init_dev(struct intel_ntb_dev *ndev) { + u32 ppd; int rc; - /* On BWD, disable all interrupts. On SNB, disable all but Link - * Interrupt. The rest will be unmasked as callbacks are registered. - */ - if (is_ntb_atom(ndev)) - writeq(~0, ndev->reg_ofs.ldb_mask); - else { - u16 var = 1 << SNB_LINK_DB; - writew(~var, ndev->reg_ofs.ldb_mask); - } - - rc = ntb_setup_msix(ndev); - if (!rc) - goto done; + rc = pci_read_config_dword(ndev->ntb.pdev, BWD_PPD_OFFSET, &ppd); + if (rc) + return -EIO; - ndev->bits_per_vector = 1; - ndev->max_cbs = ndev->limits.max_db_bits; + ndev->ntb.topo = bwd_ppd_topo(ndev, ppd); + if (ndev->ntb.topo == NTB_TOPO_NONE) + return -EINVAL; - rc = ntb_setup_msi(ndev); - if (!rc) - goto done; + rc = bwd_init_ntb(ndev); + if (rc) + return rc; - rc = ntb_setup_intx(ndev); - if (rc) { - dev_err(&ndev->pdev->dev, "no usable interrupts\n"); + rc = bwd_init_isr(ndev); + if (rc) return rc; + + if (ndev->ntb.topo != NTB_TOPO_SEC) { + /* Initiate PCI-E link training */ + rc = pci_write_config_dword(ndev->ntb.pdev, BWD_PPD_OFFSET, + ppd | BWD_PPD_INIT_LINK); + if (rc) + return rc; } -done: return 0; } -static void ntb_free_interrupts(struct ntb_device *ndev) +static void bwd_deinit_dev(struct intel_ntb_dev *ndev) { - struct pci_dev *pdev = ndev->pdev; + bwd_deinit_isr(ndev); +} - /* mask interrupts */ - if (is_ntb_atom(ndev)) - writeq(~0, ndev->reg_ofs.ldb_mask); - else - writew(~0, ndev->reg_ofs.ldb_mask); +/* SNB */ - if (ndev->num_msix) { - struct msix_entry *msix; - u32 i; +static u64 snb_db_ioread(void __iomem *mmio) +{ + return (u64)ioread16(mmio); +} - for (i = 0; i < ndev->num_msix; i++) { - msix = &ndev->msix_entries[i]; - if (is_ntb_xeon(ndev) && i == ndev->num_msix - 1) - free_irq(msix->vector, ndev); - else - free_irq(msix->vector, &ndev->db_cb[i]); - } - pci_disable_msix(pdev); - kfree(ndev->msix_entries); - } else { - free_irq(pdev->irq, ndev); +static void snb_db_iowrite(u64 bits, void __iomem *mmio) +{ + iowrite16((u16)bits, mmio); +} - if (pci_dev_msi_enabled(pdev)) - pci_disable_msi(pdev); - } +static int snb_poll_link(struct intel_ntb_dev *ndev) +{ + u16 reg_val; + int rc; + + ndev->reg->db_iowrite(ndev->db_link_mask, + ndev->self_mmio + + ndev->self_reg->db_bell); + + rc = pci_read_config_word(ndev->ntb.pdev, + SNB_LINK_STATUS_OFFSET, ®_val); + if (rc) + return 0; + + if (reg_val == ndev->lnk_sta) + return 0; + + ndev->lnk_sta = reg_val; + + return 1; } -static int ntb_create_callbacks(struct ntb_device *ndev) +static int snb_link_is_up(struct intel_ntb_dev *ndev) { - int i; + return NTB_LNK_STA_ACTIVE(ndev->lnk_sta); +} - /* Chicken-egg issue. We won't know how many callbacks are necessary - * until we see how many MSI-X vectors we get, but these pointers need - * to be passed into the MSI-X register function. So, we allocate the - * max, knowing that they might not all be used, to work around this. - */ - ndev->db_cb = kcalloc(ndev->limits.max_db_bits, - sizeof(struct ntb_db_cb), - GFP_KERNEL); - if (!ndev->db_cb) - return -ENOMEM; +static inline enum ntb_topo snb_ppd_topo(struct intel_ntb_dev *ndev, u8 ppd) +{ + switch (ppd & SNB_PPD_TOPO_MASK) { + case SNB_PPD_TOPO_B2B_USD: + return NTB_TOPO_B2B_USD; + + case SNB_PPD_TOPO_B2B_DSD: + return NTB_TOPO_B2B_DSD; + + case SNB_PPD_TOPO_PRI_USD: + case SNB_PPD_TOPO_PRI_DSD: /* accept bogus PRI_DSD */ + return NTB_TOPO_PRI; - for (i = 0; i < ndev->limits.max_db_bits; i++) { - ndev->db_cb[i].db_num = i; - ndev->db_cb[i].ndev = ndev; + case SNB_PPD_TOPO_SEC_USD: + case SNB_PPD_TOPO_SEC_DSD: /* accept bogus SEC_DSD */ + return NTB_TOPO_SEC; } - return 0; + return NTB_TOPO_NONE; } -static void ntb_free_callbacks(struct ntb_device *ndev) +static inline int snb_ppd_bar4_split(struct intel_ntb_dev *ndev, u8 ppd) { - int i; + if (ppd & SNB_PPD_SPLIT_BAR_MASK) { + dev_dbg(ndev_dev(ndev), "PPD %d split bar\n", ppd); + return 1; + } + return 0; +} - for (i = 0; i < ndev->limits.max_db_bits; i++) - ntb_unregister_db_callback(ndev, i); +static int snb_init_isr(struct intel_ntb_dev *ndev) +{ + return ndev_init_isr(ndev, SNB_DB_MSIX_VECTOR_COUNT, + SNB_DB_MSIX_VECTOR_COUNT, + SNB_DB_MSIX_VECTOR_SHIFT, + SNB_DB_TOTAL_SHIFT); +} - kfree(ndev->db_cb); +static void snb_deinit_isr(struct intel_ntb_dev *ndev) +{ + ndev_deinit_isr(ndev); } -static ssize_t ntb_debugfs_read(struct file *filp, char __user *ubuf, - size_t count, loff_t *offp) +static int snb_setup_b2b_mw(struct intel_ntb_dev *ndev, + const struct intel_b2b_addr *addr, + const struct intel_b2b_addr *peer_addr) { - struct ntb_device *ndev; - char *buf; - ssize_t ret, offset, out_count; + struct pci_dev *pdev; + void __iomem *mmio; + resource_size_t bar_size; + phys_addr_t bar_addr; + int b2b_bar; + u8 bar_sz; + + pdev = ndev_pdev(ndev); + mmio = ndev->self_mmio; + + if (ndev->b2b_idx >= ndev->mw_count) { + dev_dbg(ndev_dev(ndev), "not using b2b mw\n"); + b2b_bar = 0; + ndev->b2b_off = 0; + } else { + b2b_bar = ndev_mw_to_bar(ndev, ndev->b2b_idx); + if (b2b_bar < 0) + return -EIO; - out_count = 500; + dev_dbg(ndev_dev(ndev), "using b2b mw bar %d\n", b2b_bar); - buf = kmalloc(out_count, GFP_KERNEL); - if (!buf) - return -ENOMEM; + bar_size = pci_resource_len(ndev->ntb.pdev, b2b_bar); - ndev = filp->private_data; - offset = 0; - offset += snprintf(buf + offset, out_count - offset, - "NTB Device Information:\n"); - offset += snprintf(buf + offset, out_count - offset, - "Connection Type - \t\t%s\n", - ndev->conn_type == NTB_CONN_TRANSPARENT ? - "Transparent" : (ndev->conn_type == NTB_CONN_B2B) ? - "Back to back" : "Root Port"); - offset += snprintf(buf + offset, out_count - offset, - "Device Type - \t\t\t%s\n", - ndev->dev_type == NTB_DEV_USD ? - "DSD/USP" : "USD/DSP"); - offset += snprintf(buf + offset, out_count - offset, - "Max Number of Callbacks - \t%u\n", - ntb_max_cbs(ndev)); - offset += snprintf(buf + offset, out_count - offset, - "Link Status - \t\t\t%s\n", - ntb_hw_link_status(ndev) ? "Up" : "Down"); - if (ntb_hw_link_status(ndev)) { - offset += snprintf(buf + offset, out_count - offset, - "Link Speed - \t\t\tPCI-E Gen %u\n", - ndev->link_speed); - offset += snprintf(buf + offset, out_count - offset, - "Link Width - \t\t\tx%u\n", - ndev->link_width); - } + dev_dbg(ndev_dev(ndev), "b2b bar size %#llx\n", bar_size); - if (is_ntb_xeon(ndev)) { - u32 status32; - u16 status16; - int rc; - - offset += snprintf(buf + offset, out_count - offset, - "\nNTB Device Statistics:\n"); - offset += snprintf(buf + offset, out_count - offset, - "Upstream Memory Miss - \t%u\n", - readw(ndev->reg_base + - SNB_USMEMMISS_OFFSET)); - - offset += snprintf(buf + offset, out_count - offset, - "\nNTB Hardware Errors:\n"); - - rc = pci_read_config_word(ndev->pdev, SNB_DEVSTS_OFFSET, - &status16); - if (!rc) - offset += snprintf(buf + offset, out_count - offset, - "DEVSTS - \t%#06x\n", status16); - - rc = pci_read_config_word(ndev->pdev, SNB_LINK_STATUS_OFFSET, - &status16); - if (!rc) - offset += snprintf(buf + offset, out_count - offset, - "LNKSTS - \t%#06x\n", status16); - - rc = pci_read_config_dword(ndev->pdev, SNB_UNCERRSTS_OFFSET, - &status32); - if (!rc) - offset += snprintf(buf + offset, out_count - offset, - "UNCERRSTS - \t%#010x\n", status32); - - rc = pci_read_config_dword(ndev->pdev, SNB_CORERRSTS_OFFSET, - &status32); - if (!rc) - offset += snprintf(buf + offset, out_count - offset, - "CORERRSTS - \t%#010x\n", status32); + if (b2b_mw_share && SNB_B2B_MIN_SIZE <= bar_size >> 1) { + dev_dbg(ndev_dev(ndev), + "b2b using first half of bar\n"); + ndev->b2b_off = bar_size >> 1; + } else if (SNB_B2B_MIN_SIZE <= bar_size) { + dev_dbg(ndev_dev(ndev), + "b2b using whole bar\n"); + ndev->b2b_off = 0; + --ndev->mw_count; + } else { + dev_dbg(ndev_dev(ndev), + "b2b bar size is too small\n"); + return -EIO; + } } - if (offset > out_count) - offset = out_count; + /* Reset the secondary bar sizes to match the primary bar sizes, + * except disable or halve the size of the b2b secondary bar. + * + * Note: code for each specific bar size register, because the register + * offsets are not in a consistent order (bar5sz comes after ppd, odd). + */ + pci_read_config_byte(pdev, SNB_PBAR23SZ_OFFSET, &bar_sz); + dev_dbg(ndev_dev(ndev), "PBAR23SZ %#x\n", bar_sz); + if (b2b_bar == 2) { + if (ndev->b2b_off) + bar_sz -= 1; + else + bar_sz = 0; + } + pci_write_config_byte(pdev, SNB_SBAR23SZ_OFFSET, bar_sz); + pci_read_config_byte(pdev, SNB_SBAR23SZ_OFFSET, &bar_sz); + dev_dbg(ndev_dev(ndev), "SBAR23SZ %#x\n", bar_sz); + + if (!ndev->bar4_split) { + pci_read_config_byte(pdev, SNB_PBAR45SZ_OFFSET, &bar_sz); + dev_dbg(ndev_dev(ndev), "PBAR45SZ %#x\n", bar_sz); + if (b2b_bar == 4) { + if (ndev->b2b_off) + bar_sz -= 1; + else + bar_sz = 0; + } + pci_write_config_byte(pdev, SNB_SBAR45SZ_OFFSET, bar_sz); + pci_read_config_byte(pdev, SNB_SBAR45SZ_OFFSET, &bar_sz); + dev_dbg(ndev_dev(ndev), "SBAR45SZ %#x\n", bar_sz); + } else { + pci_read_config_byte(pdev, SNB_PBAR4SZ_OFFSET, &bar_sz); + dev_dbg(ndev_dev(ndev), "PBAR4SZ %#x\n", bar_sz); + if (b2b_bar == 4) { + if (ndev->b2b_off) + bar_sz -= 1; + else + bar_sz = 0; + } + pci_write_config_byte(pdev, SNB_SBAR4SZ_OFFSET, bar_sz); + pci_read_config_byte(pdev, SNB_SBAR4SZ_OFFSET, &bar_sz); + dev_dbg(ndev_dev(ndev), "SBAR4SZ %#x\n", bar_sz); + + pci_read_config_byte(pdev, SNB_PBAR5SZ_OFFSET, &bar_sz); + dev_dbg(ndev_dev(ndev), "PBAR5SZ %#x\n", bar_sz); + if (b2b_bar == 5) { + if (ndev->b2b_off) + bar_sz -= 1; + else + bar_sz = 0; + } + pci_write_config_byte(pdev, SNB_SBAR5SZ_OFFSET, bar_sz); + pci_read_config_byte(pdev, SNB_SBAR5SZ_OFFSET, &bar_sz); + dev_dbg(ndev_dev(ndev), "SBAR5SZ %#x\n", bar_sz); + } - ret = simple_read_from_buffer(ubuf, count, offp, buf, offset); - kfree(buf); - return ret; -} + /* SBAR01 hit by first part of the b2b bar */ + if (b2b_bar == 0) + bar_addr = addr->bar0_addr; + else if (b2b_bar == 2) + bar_addr = addr->bar2_addr64; + else if (b2b_bar == 4 && !ndev->bar4_split) + bar_addr = addr->bar4_addr64; + else if (b2b_bar == 4) + bar_addr = addr->bar4_addr32; + else if (b2b_bar == 5) + bar_addr = addr->bar5_addr32; + else + return -EIO; -static const struct file_operations ntb_debugfs_info = { - .owner = THIS_MODULE, - .open = simple_open, - .read = ntb_debugfs_read, -}; + dev_dbg(ndev_dev(ndev), "SBAR01 %#018llx\n", bar_addr); + iowrite64(bar_addr, mmio + SNB_SBAR0BASE_OFFSET); -static void ntb_setup_debugfs(struct ntb_device *ndev) -{ - if (!debugfs_initialized()) - return; + /* Other SBAR are normally hit by the PBAR xlat, except for b2b bar. + * The b2b bar is either disabled above, or configured half-size, and + * it starts at the PBAR xlat + offset. + */ - if (!debugfs_dir) - debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL); + bar_addr = addr->bar2_addr64 + (b2b_bar == 2 ? ndev->b2b_off : 0); + iowrite64(bar_addr, mmio + SNB_SBAR23BASE_OFFSET); + bar_addr = ioread64(mmio + SNB_SBAR23BASE_OFFSET); + dev_dbg(ndev_dev(ndev), "SBAR23 %#018llx\n", bar_addr); + + if (!ndev->bar4_split) { + bar_addr = addr->bar4_addr64 + + (b2b_bar == 4 ? ndev->b2b_off : 0); + iowrite64(bar_addr, mmio + SNB_SBAR45BASE_OFFSET); + bar_addr = ioread64(mmio + SNB_SBAR45BASE_OFFSET); + dev_dbg(ndev_dev(ndev), "SBAR45 %#018llx\n", bar_addr); + } else { + bar_addr = addr->bar4_addr32 + + (b2b_bar == 4 ? ndev->b2b_off : 0); + iowrite32(bar_addr, mmio + SNB_SBAR4BASE_OFFSET); + bar_addr = ioread32(mmio + SNB_SBAR4BASE_OFFSET); + dev_dbg(ndev_dev(ndev), "SBAR4 %#010llx\n", bar_addr); + + bar_addr = addr->bar5_addr32 + + (b2b_bar == 5 ? ndev->b2b_off : 0); + iowrite32(bar_addr, mmio + SNB_SBAR5BASE_OFFSET); + bar_addr = ioread32(mmio + SNB_SBAR5BASE_OFFSET); + dev_dbg(ndev_dev(ndev), "SBAR5 %#010llx\n", bar_addr); + } - ndev->debugfs_dir = debugfs_create_dir(pci_name(ndev->pdev), - debugfs_dir); - if (ndev->debugfs_dir) - ndev->debugfs_info = debugfs_create_file("info", S_IRUSR, - ndev->debugfs_dir, - ndev, - &ntb_debugfs_info); -} + /* setup incoming bar limits == base addrs (zero length windows) */ -static void ntb_free_debugfs(struct ntb_device *ndev) -{ - debugfs_remove_recursive(ndev->debugfs_dir); + bar_addr = addr->bar2_addr64 + (b2b_bar == 2 ? ndev->b2b_off : 0); + iowrite64(bar_addr, mmio + SNB_SBAR23LMT_OFFSET); + bar_addr = ioread64(mmio + SNB_SBAR23LMT_OFFSET); + dev_dbg(ndev_dev(ndev), "SBAR23LMT %#018llx\n", bar_addr); - if (debugfs_dir && simple_empty(debugfs_dir)) { - debugfs_remove_recursive(debugfs_dir); - debugfs_dir = NULL; + if (!ndev->bar4_split) { + bar_addr = addr->bar4_addr64 + + (b2b_bar == 4 ? ndev->b2b_off : 0); + iowrite64(bar_addr, mmio + SNB_SBAR45LMT_OFFSET); + bar_addr = ioread64(mmio + SNB_SBAR45LMT_OFFSET); + dev_dbg(ndev_dev(ndev), "SBAR45LMT %#018llx\n", bar_addr); + } else { + bar_addr = addr->bar4_addr32 + + (b2b_bar == 4 ? ndev->b2b_off : 0); + iowrite32(bar_addr, mmio + SNB_SBAR4LMT_OFFSET); + bar_addr = ioread32(mmio + SNB_SBAR4LMT_OFFSET); + dev_dbg(ndev_dev(ndev), "SBAR4LMT %#010llx\n", bar_addr); + + bar_addr = addr->bar5_addr32 + + (b2b_bar == 5 ? ndev->b2b_off : 0); + iowrite32(bar_addr, mmio + SNB_SBAR5LMT_OFFSET); + bar_addr = ioread32(mmio + SNB_SBAR5LMT_OFFSET); + dev_dbg(ndev_dev(ndev), "SBAR5LMT %#05llx\n", bar_addr); } -} -static void ntb_hw_link_up(struct ntb_device *ndev) -{ - if (ndev->conn_type == NTB_CONN_TRANSPARENT) - ntb_link_event(ndev, NTB_LINK_UP); - else { - u32 ntb_cntl; + /* zero incoming translation addrs */ + iowrite64(0, mmio + SNB_SBAR23XLAT_OFFSET); - /* Let's bring the NTB link up */ - ntb_cntl = readl(ndev->reg_ofs.lnk_cntl); - ntb_cntl &= ~(NTB_CNTL_LINK_DISABLE | NTB_CNTL_CFG_LOCK); - ntb_cntl |= NTB_CNTL_P2S_BAR23_SNOOP | NTB_CNTL_S2P_BAR23_SNOOP; - ntb_cntl |= NTB_CNTL_P2S_BAR4_SNOOP | NTB_CNTL_S2P_BAR4_SNOOP; - if (ndev->split_bar) - ntb_cntl |= NTB_CNTL_P2S_BAR5_SNOOP | - NTB_CNTL_S2P_BAR5_SNOOP; + if (!ndev->bar4_split) { + iowrite64(0, mmio + SNB_SBAR45XLAT_OFFSET); + } else { + iowrite32(0, mmio + SNB_SBAR4XLAT_OFFSET); + iowrite32(0, mmio + SNB_SBAR5XLAT_OFFSET); + } - writel(ntb_cntl, ndev->reg_ofs.lnk_cntl); + /* zero outgoing translation limits (whole bar size windows) */ + iowrite64(0, mmio + SNB_PBAR23LMT_OFFSET); + if (!ndev->bar4_split) { + iowrite64(0, mmio + SNB_PBAR45LMT_OFFSET); + } else { + iowrite32(0, mmio + SNB_PBAR4LMT_OFFSET); + iowrite32(0, mmio + SNB_PBAR5LMT_OFFSET); } -} -static void ntb_hw_link_down(struct ntb_device *ndev) -{ - u32 ntb_cntl; + /* set outgoing translation offsets */ + bar_addr = peer_addr->bar2_addr64; + iowrite64(bar_addr, mmio + SNB_PBAR23XLAT_OFFSET); + bar_addr = ioread64(mmio + SNB_PBAR23XLAT_OFFSET); + dev_dbg(ndev_dev(ndev), "PBAR23XLAT %#018llx\n", bar_addr); + + if (!ndev->bar4_split) { + bar_addr = peer_addr->bar4_addr64; + iowrite64(bar_addr, mmio + SNB_PBAR45XLAT_OFFSET); + bar_addr = ioread64(mmio + SNB_PBAR45XLAT_OFFSET); + dev_dbg(ndev_dev(ndev), "PBAR45XLAT %#018llx\n", bar_addr); + } else { + bar_addr = peer_addr->bar4_addr32; + iowrite32(bar_addr, mmio + SNB_PBAR4XLAT_OFFSET); + bar_addr = ioread32(mmio + SNB_PBAR4XLAT_OFFSET); + dev_dbg(ndev_dev(ndev), "PBAR4XLAT %#010llx\n", bar_addr); + + bar_addr = peer_addr->bar5_addr32; + iowrite32(bar_addr, mmio + SNB_PBAR5XLAT_OFFSET); + bar_addr = ioread32(mmio + SNB_PBAR5XLAT_OFFSET); + dev_dbg(ndev_dev(ndev), "PBAR5XLAT %#010llx\n", bar_addr); + } - if (ndev->conn_type == NTB_CONN_TRANSPARENT) { - ntb_link_event(ndev, NTB_LINK_DOWN); - return; + /* set the translation offset for b2b registers */ + if (b2b_bar == 0) + bar_addr = peer_addr->bar0_addr; + else if (b2b_bar == 2) + bar_addr = peer_addr->bar2_addr64; + else if (b2b_bar == 4 && !ndev->bar4_split) + bar_addr = peer_addr->bar4_addr64; + else if (b2b_bar == 4) + bar_addr = peer_addr->bar4_addr32; + else if (b2b_bar == 5) + bar_addr = peer_addr->bar5_addr32; + else + return -EIO; + + /* B2B_XLAT_OFFSET is 64bit, but can only take 32bit writes */ + dev_dbg(ndev_dev(ndev), "B2BXLAT %#018llx\n", bar_addr); + iowrite32(bar_addr, mmio + SNB_B2B_XLAT_OFFSETL); + iowrite32(bar_addr >> 32, mmio + SNB_B2B_XLAT_OFFSETU); + + if (b2b_bar) { + /* map peer ntb mmio config space registers */ + ndev->peer_mmio = pci_iomap(pdev, b2b_bar, + SNB_B2B_MIN_SIZE); + if (!ndev->peer_mmio) + return -EIO; } - /* Bring NTB link down */ - ntb_cntl = readl(ndev->reg_ofs.lnk_cntl); - ntb_cntl &= ~(NTB_CNTL_P2S_BAR23_SNOOP | NTB_CNTL_S2P_BAR23_SNOOP); - ntb_cntl &= ~(NTB_CNTL_P2S_BAR4_SNOOP | NTB_CNTL_S2P_BAR4_SNOOP); - if (ndev->split_bar) - ntb_cntl &= ~(NTB_CNTL_P2S_BAR5_SNOOP | - NTB_CNTL_S2P_BAR5_SNOOP); - ntb_cntl |= NTB_CNTL_LINK_DISABLE | NTB_CNTL_CFG_LOCK; - writel(ntb_cntl, ndev->reg_ofs.lnk_cntl); + return 0; } -static void ntb_max_mw_detect(struct ntb_device *ndev) +static int snb_init_ntb(struct intel_ntb_dev *ndev) { - if (ndev->split_bar) - ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW; + int rc; + + if (ndev->bar4_split) + ndev->mw_count = HSX_SPLIT_BAR_MW_COUNT; else - ndev->limits.max_mw = SNB_MAX_MW; -} + ndev->mw_count = SNB_MW_COUNT; -static int ntb_xeon_detect(struct ntb_device *ndev) -{ - int rc, bars_mask; - u32 bars; - u8 ppd; + ndev->spad_count = SNB_SPAD_COUNT; + ndev->db_count = SNB_DB_COUNT; + ndev->db_link_mask = SNB_DB_LINK_BIT; - ndev->hw_type = SNB_HW; + switch (ndev->ntb.topo) { + case NTB_TOPO_PRI: + if (ndev->hwerr_flags & NTB_HWERR_SDOORBELL_LOCKUP) { + dev_err(ndev_dev(ndev), "NTB Primary config disabled\n"); + return -EINVAL; + } + /* use half the spads for the peer */ + ndev->spad_count >>= 1; + ndev->self_reg = &snb_pri_reg; + ndev->peer_reg = &snb_sec_reg; + ndev->xlat_reg = &snb_sec_xlat; + break; - rc = pci_read_config_byte(ndev->pdev, NTB_PPD_OFFSET, &ppd); - if (rc) - return -EIO; + case NTB_TOPO_SEC: + if (ndev->hwerr_flags & NTB_HWERR_SDOORBELL_LOCKUP) { + dev_err(ndev_dev(ndev), "NTB Secondary config disabled\n"); + return -EINVAL; + } + /* use half the spads for the peer */ + ndev->spad_count >>= 1; + ndev->self_reg = &snb_sec_reg; + ndev->peer_reg = &snb_pri_reg; + ndev->xlat_reg = &snb_pri_xlat; + break; - if (ppd & SNB_PPD_DEV_TYPE) - ndev->dev_type = NTB_DEV_USD; - else - ndev->dev_type = NTB_DEV_DSD; + case NTB_TOPO_B2B_USD: + case NTB_TOPO_B2B_DSD: + ndev->self_reg = &snb_pri_reg; + ndev->peer_reg = &snb_b2b_reg; + ndev->xlat_reg = &snb_sec_xlat; - ndev->split_bar = (ppd & SNB_PPD_SPLIT_BAR) ? 1 : 0; + if (ndev->hwerr_flags & NTB_HWERR_SDOORBELL_LOCKUP) { + ndev->peer_reg = &snb_pri_reg; - switch (ppd & SNB_PPD_CONN_TYPE) { - case NTB_CONN_B2B: - dev_info(&ndev->pdev->dev, "Conn Type = B2B\n"); - ndev->conn_type = NTB_CONN_B2B; - break; - case NTB_CONN_RP: - dev_info(&ndev->pdev->dev, "Conn Type = RP\n"); - ndev->conn_type = NTB_CONN_RP; - break; - case NTB_CONN_TRANSPARENT: - dev_info(&ndev->pdev->dev, "Conn Type = TRANSPARENT\n"); - ndev->conn_type = NTB_CONN_TRANSPARENT; - /* - * This mode is default to USD/DSP. HW does not report - * properly in transparent mode as it has no knowledge of - * NTB. We will just force correct here. - */ - ndev->dev_type = NTB_DEV_USD; + if (b2b_mw_idx < 0) + ndev->b2b_idx = b2b_mw_idx + ndev->mw_count; + else + ndev->b2b_idx = b2b_mw_idx; - /* - * This is a way for transparent BAR to figure out if we - * are doing split BAR or not. There is no way for the hw - * on the transparent side to know and set the PPD. - */ - bars_mask = pci_select_bars(ndev->pdev, IORESOURCE_MEM); - bars = hweight32(bars_mask); - if (bars == (HSX_SPLITBAR_MAX_MW + 1)) - ndev->split_bar = 1; + dev_dbg(ndev_dev(ndev), + "setting up b2b mw idx %d means %d\n", + b2b_mw_idx, ndev->b2b_idx); + + } else if (ndev->hwerr_flags & NTB_HWERR_B2BDOORBELL_BIT14) { + dev_warn(ndev_dev(ndev), "Reduce doorbell count by 1\n"); + ndev->db_count -= 1; + } + + if (ndev->ntb.topo == NTB_TOPO_B2B_USD) { + rc = snb_setup_b2b_mw(ndev, + &snb_b2b_dsd_addr, + &snb_b2b_usd_addr); + } else { + rc = snb_setup_b2b_mw(ndev, + &snb_b2b_usd_addr, + &snb_b2b_dsd_addr); + } + if (rc) + return rc; + + /* Enable Bus Master and Memory Space on the secondary side */ + iowrite16(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER, + ndev->self_mmio + SNB_SPCICMD_OFFSET); break; + default: - dev_err(&ndev->pdev->dev, "Unknown PPD %x\n", ppd); - return -ENODEV; + return -EINVAL; } - ntb_max_mw_detect(ndev); + ndev->db_valid_mask = BIT_ULL(ndev->db_count) - 1; + + ndev->reg->db_iowrite(ndev->db_valid_mask, + ndev->self_mmio + + ndev->self_reg->db_mask); return 0; } -static int ntb_atom_detect(struct ntb_device *ndev) +static int snb_init_dev(struct intel_ntb_dev *ndev) { - int rc; - u32 ppd; + struct pci_dev *pdev; + u8 ppd; + int rc, mem; + + /* There is a Xeon hardware errata related to writes to SDOORBELL or + * B2BDOORBELL in conjunction with inbound access to NTB MMIO Space, + * which may hang the system. To workaround this use the second memory + * window to access the interrupt and scratch pad registers on the + * remote system. + */ + ndev->hwerr_flags |= NTB_HWERR_SDOORBELL_LOCKUP; - ndev->hw_type = BWD_HW; - ndev->limits.max_mw = BWD_MAX_MW; + /* There is a hardware errata related to accessing any register in + * SB01BASE in the presence of bidirectional traffic crossing the NTB. + */ + ndev->hwerr_flags |= NTB_HWERR_SB01BASE_LOCKUP; + + /* HW Errata on bit 14 of b2bdoorbell register. Writes will not be + * mirrored to the remote system. Shrink the number of bits by one, + * since bit 14 is the last bit. + */ + ndev->hwerr_flags |= NTB_HWERR_B2BDOORBELL_BIT14; - rc = pci_read_config_dword(ndev->pdev, NTB_PPD_OFFSET, &ppd); + ndev->reg = &snb_reg; + + pdev = ndev_pdev(ndev); + + rc = pci_read_config_byte(pdev, SNB_PPD_OFFSET, &ppd); if (rc) - return rc; + return -EIO; - switch ((ppd & BWD_PPD_CONN_TYPE) >> 8) { - case NTB_CONN_B2B: - dev_info(&ndev->pdev->dev, "Conn Type = B2B\n"); - ndev->conn_type = NTB_CONN_B2B; - break; - case NTB_CONN_RP: - default: - dev_err(&ndev->pdev->dev, "Unsupported NTB configuration\n"); + ndev->ntb.topo = snb_ppd_topo(ndev, ppd); + dev_dbg(ndev_dev(ndev), "ppd %#x topo %s\n", ppd, + ntb_topo_string(ndev->ntb.topo)); + if (ndev->ntb.topo == NTB_TOPO_NONE) return -EINVAL; + + if (ndev->ntb.topo != NTB_TOPO_SEC) { + ndev->bar4_split = snb_ppd_bar4_split(ndev, ppd); + dev_dbg(ndev_dev(ndev), "ppd %#x bar4_split %d\n", + ppd, ndev->bar4_split); + } else { + /* This is a way for transparent BAR to figure out if we are + * doing split BAR or not. There is no way for the hw on the + * transparent side to know and set the PPD. + */ + mem = pci_select_bars(pdev, IORESOURCE_MEM); + ndev->bar4_split = hweight32(mem) == + HSX_SPLIT_BAR_MW_COUNT + 1; + dev_dbg(ndev_dev(ndev), "mem %#x bar4_split %d\n", + mem, ndev->bar4_split); } - if (ppd & BWD_PPD_DEV_TYPE) - ndev->dev_type = NTB_DEV_DSD; - else - ndev->dev_type = NTB_DEV_USD; + rc = snb_init_ntb(ndev); + if (rc) + return rc; - return 0; + return snb_init_isr(ndev); +} + +static void snb_deinit_dev(struct intel_ntb_dev *ndev) +{ + snb_deinit_isr(ndev); } -static int ntb_device_detect(struct ntb_device *ndev) +static int intel_ntb_init_pci(struct intel_ntb_dev *ndev, struct pci_dev *pdev) { int rc; - if (is_ntb_xeon(ndev)) - rc = ntb_xeon_detect(ndev); - else if (is_ntb_atom(ndev)) - rc = ntb_atom_detect(ndev); - else - rc = -ENODEV; + pci_set_drvdata(pdev, ndev); + + rc = pci_enable_device(pdev); + if (rc) + goto err_pci_enable; + + rc = pci_request_regions(pdev, NTB_NAME); + if (rc) + goto err_pci_regions; + + pci_set_master(pdev); + + rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); + if (rc) { + rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (rc) + goto err_dma_mask; + dev_warn(ndev_dev(ndev), "Cannot DMA highmem\n"); + } - dev_info(&ndev->pdev->dev, "Device Type = %s\n", - ndev->dev_type == NTB_DEV_USD ? "USD/DSP" : "DSD/USP"); + rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); + if (rc) { + rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + if (rc) + goto err_dma_mask; + dev_warn(ndev_dev(ndev), "Cannot DMA consistent highmem\n"); + } + + ndev->self_mmio = pci_iomap(pdev, 0, 0); + if (!ndev->self_mmio) { + rc = -EIO; + goto err_mmio; + } + ndev->peer_mmio = ndev->self_mmio; return 0; + +err_mmio: +err_dma_mask: + pci_clear_master(pdev); + pci_release_regions(pdev); +err_pci_regions: + pci_disable_device(pdev); +err_pci_enable: + pci_set_drvdata(pdev, NULL); + return rc; } -static int ntb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) +static void intel_ntb_deinit_pci(struct intel_ntb_dev *ndev) { - struct ntb_device *ndev; - int rc, i; + struct pci_dev *pdev = ndev_pdev(ndev); - ndev = kzalloc(sizeof(struct ntb_device), GFP_KERNEL); - if (!ndev) - return -ENOMEM; + if (ndev->peer_mmio && ndev->peer_mmio != ndev->self_mmio) + pci_iounmap(pdev, ndev->peer_mmio); + pci_iounmap(pdev, ndev->self_mmio); - ndev->pdev = pdev; + pci_clear_master(pdev); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); +} - ntb_set_errata_flags(ndev); +static inline void ndev_init_struct(struct intel_ntb_dev *ndev, + struct pci_dev *pdev) +{ + ndev->ntb.pdev = pdev; + ndev->ntb.topo = NTB_TOPO_NONE; + ndev->ntb.ops = &intel_ntb_ops; - ndev->link_status = NTB_LINK_DOWN; - pci_set_drvdata(pdev, ndev); - ntb_setup_debugfs(ndev); + ndev->b2b_off = 0; + ndev->b2b_idx = INT_MAX; - rc = pci_enable_device(pdev); - if (rc) - goto err; + ndev->bar4_split = 0; - pci_set_master(ndev->pdev); + ndev->mw_count = 0; + ndev->spad_count = 0; + ndev->db_count = 0; + ndev->db_vec_count = 0; + ndev->db_vec_shift = 0; - rc = ntb_device_detect(ndev); - if (rc) - goto err; + ndev->ntb_ctl = 0; + ndev->lnk_sta = 0; - ndev->mw = kcalloc(ndev->limits.max_mw, sizeof(struct ntb_mw), - GFP_KERNEL); - if (!ndev->mw) { - rc = -ENOMEM; - goto err1; - } + ndev->db_valid_mask = 0; + ndev->db_link_mask = 0; + ndev->db_mask = 0; - if (ndev->split_bar) - rc = pci_request_selected_regions(pdev, NTB_SPLITBAR_MASK, - KBUILD_MODNAME); - else - rc = pci_request_selected_regions(pdev, NTB_BAR_MASK, - KBUILD_MODNAME); + spin_lock_init(&ndev->db_mask_lock); +} - if (rc) - goto err2; +static int intel_ntb_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct intel_ntb_dev *ndev; + int rc; - ndev->reg_base = pci_ioremap_bar(pdev, NTB_BAR_MMIO); - if (!ndev->reg_base) { - dev_warn(&pdev->dev, "Cannot remap BAR 0\n"); - rc = -EIO; - goto err3; - } + if (pdev_is_bwd(pdev)) { + ndev = kzalloc(sizeof(*ndev), GFP_KERNEL); + if (!ndev) { + rc = -ENOMEM; + goto err_ndev; + } - for (i = 0; i < ndev->limits.max_mw; i++) { - ndev->mw[i].bar_sz = pci_resource_len(pdev, MW_TO_BAR(i)); + ndev_init_struct(ndev, pdev); - /* - * with the errata we need to steal last of the memory - * windows for workarounds and they point to MMIO registers. - */ - if ((ndev->wa_flags & WA_SNB_ERR) && - (i == (ndev->limits.max_mw - 1))) { - ndev->mw[i].vbase = - ioremap_nocache(pci_resource_start(pdev, - MW_TO_BAR(i)), - ndev->mw[i].bar_sz); - } else { - ndev->mw[i].vbase = - ioremap_wc(pci_resource_start(pdev, - MW_TO_BAR(i)), - ndev->mw[i].bar_sz); - } + rc = intel_ntb_init_pci(ndev, pdev); + if (rc) + goto err_init_pci; + + rc = bwd_init_dev(ndev); + if (rc) + goto err_init_dev; - dev_info(&pdev->dev, "MW %d size %llu\n", i, - (unsigned long long) ndev->mw[i].bar_sz); - if (!ndev->mw[i].vbase) { - dev_warn(&pdev->dev, "Cannot remap BAR %d\n", - MW_TO_BAR(i)); - rc = -EIO; - goto err4; + } else if (pdev_is_snb(pdev)) { + ndev = kzalloc(sizeof(*ndev), GFP_KERNEL); + if (!ndev) { + rc = -ENOMEM; + goto err_ndev; } - } - rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); - if (rc) { - rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (rc) - goto err4; + ndev_init_struct(ndev, pdev); - dev_warn(&pdev->dev, "Cannot DMA highmem\n"); - } + rc = intel_ntb_init_pci(ndev, pdev); + if (rc) + goto err_init_pci; - rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); - if (rc) { - rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + rc = snb_init_dev(ndev); if (rc) - goto err4; + goto err_init_dev; - dev_warn(&pdev->dev, "Cannot DMA consistent highmem\n"); + } else { + rc = -EINVAL; + goto err_ndev; } - rc = ntb_device_setup(ndev); - if (rc) - goto err4; - - rc = ntb_create_callbacks(ndev); - if (rc) - goto err5; + ndev_reset_unsafe_flags(ndev); - rc = ntb_setup_interrupts(ndev); - if (rc) - goto err6; + ndev->reg->poll_link(ndev); - /* The scratchpad registers keep the values between rmmod/insmod, - * blast them now - */ - for (i = 0; i < ndev->limits.max_spads; i++) { - ntb_write_local_spad(ndev, i, 0); - ntb_write_remote_spad(ndev, i, 0); - } + ndev_init_debugfs(ndev); - rc = ntb_transport_init(pdev); + rc = ntb_register_device(&ndev->ntb); if (rc) - goto err7; - - ntb_hw_link_up(ndev); + goto err_register; return 0; -err7: - ntb_free_interrupts(ndev); -err6: - ntb_free_callbacks(ndev); -err5: - ntb_device_free(ndev); -err4: - for (i--; i >= 0; i--) - iounmap(ndev->mw[i].vbase); - iounmap(ndev->reg_base); -err3: - if (ndev->split_bar) - pci_release_selected_regions(pdev, NTB_SPLITBAR_MASK); - else - pci_release_selected_regions(pdev, NTB_BAR_MASK); -err2: - kfree(ndev->mw); -err1: - pci_disable_device(pdev); -err: - ntb_free_debugfs(ndev); +err_register: + ndev_deinit_debugfs(ndev); + if (pdev_is_bwd(pdev)) + bwd_deinit_dev(ndev); + else if (pdev_is_snb(pdev)) + snb_deinit_dev(ndev); +err_init_dev: + intel_ntb_deinit_pci(ndev); +err_init_pci: kfree(ndev); - - dev_err(&pdev->dev, "Error loading %s module\n", KBUILD_MODNAME); +err_ndev: return rc; } -static void ntb_pci_remove(struct pci_dev *pdev) +static void intel_ntb_pci_remove(struct pci_dev *pdev) { - struct ntb_device *ndev = pci_get_drvdata(pdev); - int i; + struct intel_ntb_dev *ndev = pci_get_drvdata(pdev); + + ntb_unregister_device(&ndev->ntb); + ndev_deinit_debugfs(ndev); + if (pdev_is_bwd(pdev)) + bwd_deinit_dev(ndev); + else if (pdev_is_snb(pdev)) + snb_deinit_dev(ndev); + intel_ntb_deinit_pci(ndev); + kfree(ndev); +} - ntb_hw_link_down(ndev); +static const struct intel_ntb_reg bwd_reg = { + .poll_link = bwd_poll_link, + .link_is_up = bwd_link_is_up, + .db_ioread = bwd_db_ioread, + .db_iowrite = bwd_db_iowrite, + .db_size = sizeof(u64), + .ntb_ctl = BWD_NTBCNTL_OFFSET, + .mw_bar = {2, 4}, +}; - ntb_transport_free(ndev->ntb_transport); +static const struct intel_ntb_alt_reg bwd_pri_reg = { + .db_bell = BWD_PDOORBELL_OFFSET, + .db_mask = BWD_PDBMSK_OFFSET, + .spad = BWD_SPAD_OFFSET, +}; - ntb_free_interrupts(ndev); - ntb_free_callbacks(ndev); - ntb_device_free(ndev); +static const struct intel_ntb_alt_reg bwd_b2b_reg = { + .db_bell = BWD_B2B_DOORBELL_OFFSET, + .spad = BWD_B2B_SPAD_OFFSET, +}; - /* need to reset max_mw limits so we can unmap properly */ - if (ndev->hw_type == SNB_HW) - ntb_max_mw_detect(ndev); +static const struct intel_ntb_xlat_reg bwd_sec_xlat = { + /* FIXME : .bar0_base = BWD_SBAR0BASE_OFFSET, */ + /* FIXME : .bar2_limit = BWD_SBAR2LMT_OFFSET, */ + .bar2_xlat = BWD_SBAR2XLAT_OFFSET, +}; - for (i = 0; i < ndev->limits.max_mw; i++) - iounmap(ndev->mw[i].vbase); +static const struct intel_ntb_reg snb_reg = { + .poll_link = snb_poll_link, + .link_is_up = snb_link_is_up, + .db_ioread = snb_db_ioread, + .db_iowrite = snb_db_iowrite, + .db_size = sizeof(u32), + .ntb_ctl = SNB_NTBCNTL_OFFSET, + .mw_bar = {2, 4, 5}, +}; - kfree(ndev->mw); - iounmap(ndev->reg_base); - if (ndev->split_bar) - pci_release_selected_regions(pdev, NTB_SPLITBAR_MASK); - else - pci_release_selected_regions(pdev, NTB_BAR_MASK); - pci_disable_device(pdev); - ntb_free_debugfs(ndev); - kfree(ndev); -} +static const struct intel_ntb_alt_reg snb_pri_reg = { + .db_bell = SNB_PDOORBELL_OFFSET, + .db_mask = SNB_PDBMSK_OFFSET, + .spad = SNB_SPAD_OFFSET, +}; + +static const struct intel_ntb_alt_reg snb_sec_reg = { + .db_bell = SNB_SDOORBELL_OFFSET, + .db_mask = SNB_SDBMSK_OFFSET, + /* second half of the scratchpads */ + .spad = SNB_SPAD_OFFSET + (SNB_SPAD_COUNT << 1), +}; -static struct pci_driver ntb_pci_driver = { +static const struct intel_ntb_alt_reg snb_b2b_reg = { + .db_bell = SNB_B2B_DOORBELL_OFFSET, + .spad = SNB_B2B_SPAD_OFFSET, +}; + +static const struct intel_ntb_xlat_reg snb_pri_xlat = { + /* Note: no primary .bar0_base visible to the secondary side. + * + * The secondary side cannot get the base address stored in primary + * bars. The base address is necessary to set the limit register to + * any value other than zero, or unlimited. + * + * WITHOUT THE BASE ADDRESS, THE SECONDARY SIDE CANNOT DISABLE the + * window by setting the limit equal to base, nor can it limit the size + * of the memory window by setting the limit to base + size. + */ + .bar2_limit = SNB_PBAR23LMT_OFFSET, + .bar2_xlat = SNB_PBAR23XLAT_OFFSET, +}; + +static const struct intel_ntb_xlat_reg snb_sec_xlat = { + .bar0_base = SNB_SBAR0BASE_OFFSET, + .bar2_limit = SNB_SBAR23LMT_OFFSET, + .bar2_xlat = SNB_SBAR23XLAT_OFFSET, +}; + +static const struct intel_b2b_addr snb_b2b_usd_addr = { + .bar2_addr64 = SNB_B2B_BAR2_USD_ADDR64, + .bar4_addr64 = SNB_B2B_BAR4_USD_ADDR64, + .bar4_addr32 = SNB_B2B_BAR4_USD_ADDR32, + .bar5_addr32 = SNB_B2B_BAR5_USD_ADDR32, +}; + +static const struct intel_b2b_addr snb_b2b_dsd_addr = { + .bar2_addr64 = SNB_B2B_BAR2_DSD_ADDR64, + .bar4_addr64 = SNB_B2B_BAR4_DSD_ADDR64, + .bar4_addr32 = SNB_B2B_BAR4_DSD_ADDR32, + .bar5_addr32 = SNB_B2B_BAR5_DSD_ADDR32, +}; + +/* operations for primary side of local ntb */ +static const struct ntb_dev_ops intel_ntb_ops = { + .mw_count = intel_ntb_mw_count, + .mw_get_range = intel_ntb_mw_get_range, + .mw_set_trans = intel_ntb_mw_set_trans, + .link_is_up = intel_ntb_link_is_up, + .link_enable = intel_ntb_link_enable, + .link_disable = intel_ntb_link_disable, + .db_is_unsafe = intel_ntb_db_is_unsafe, + .db_valid_mask = intel_ntb_db_valid_mask, + .db_vector_count = intel_ntb_db_vector_count, + .db_vector_mask = intel_ntb_db_vector_mask, + .db_read = intel_ntb_db_read, + .db_clear = intel_ntb_db_clear, + .db_set_mask = intel_ntb_db_set_mask, + .db_clear_mask = intel_ntb_db_clear_mask, + .peer_db_addr = intel_ntb_peer_db_addr, + .peer_db_set = intel_ntb_peer_db_set, + .spad_is_unsafe = intel_ntb_spad_is_unsafe, + .spad_count = intel_ntb_spad_count, + .spad_read = intel_ntb_spad_read, + .spad_write = intel_ntb_spad_write, + .peer_spad_addr = intel_ntb_peer_spad_addr, + .peer_spad_read = intel_ntb_peer_spad_read, + .peer_spad_write = intel_ntb_peer_spad_write, +}; + +static const struct file_operations intel_ntb_debugfs_info = { + .owner = THIS_MODULE, + .open = simple_open, + .read = ndev_debugfs_read, +}; + +static const struct pci_device_id intel_ntb_pci_tbl[] = { + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_BWD)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_JSF)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_SNB)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_IVT)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_HSX)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_JSF)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_SNB)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_IVT)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_HSX)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_JSF)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_SNB)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_IVT)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_HSX)}, + {0} +}; +MODULE_DEVICE_TABLE(pci, intel_ntb_pci_tbl); + +static struct pci_driver intel_ntb_pci_driver = { .name = KBUILD_MODNAME, - .id_table = ntb_pci_tbl, - .probe = ntb_pci_probe, - .remove = ntb_pci_remove, + .id_table = intel_ntb_pci_tbl, + .probe = intel_ntb_pci_probe, + .remove = intel_ntb_pci_remove, }; -module_pci_driver(ntb_pci_driver); +static int __init intel_ntb_pci_driver_init(void) +{ + if (debugfs_initialized()) + debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL); + + return pci_register_driver(&intel_ntb_pci_driver); +} +module_init(intel_ntb_pci_driver_init); + +static void __exit intel_ntb_pci_driver_exit(void) +{ + pci_unregister_driver(&intel_ntb_pci_driver); + + debugfs_remove_recursive(debugfs_dir); +} +module_exit(intel_ntb_pci_driver_exit); + diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.h b/drivers/ntb/hw/intel/ntb_hw_intel.h index 935610454f70..fec689dc95cf 100644 --- a/drivers/ntb/hw/intel/ntb_hw_intel.h +++ b/drivers/ntb/hw/intel/ntb_hw_intel.h @@ -5,6 +5,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 Intel Corporation. All rights reserved. + * Copyright (C) 2015 EMC Corporation. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -13,6 +14,7 @@ * BSD LICENSE * * Copyright(c) 2012 Intel Corporation. All rights reserved. + * Copyright (C) 2015 EMC Corporation. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -45,341 +47,296 @@ * Contact Information: * Jon Mason */ -#include - -#define NTB_LINK_STATUS_ACTIVE 0x2000 -#define NTB_LINK_SPEED_MASK 0x000f -#define NTB_LINK_WIDTH_MASK 0x03f0 - -#define SNB_MSIX_CNT 4 -#define SNB_MAX_B2B_SPADS 16 -#define SNB_MAX_COMPAT_SPADS 16 -/* Reserve the uppermost bit for link interrupt */ -#define SNB_MAX_DB_BITS 15 -#define SNB_LINK_DB 15 -#define SNB_DB_BITS_PER_VEC 5 -#define HSX_SPLITBAR_MAX_MW 3 -#define SNB_MAX_MW 2 -#define SNB_ERRATA_MAX_MW 1 - -#define SNB_DB_HW_LINK 0x8000 - -#define SNB_UNCERRSTS_OFFSET 0x014C -#define SNB_CORERRSTS_OFFSET 0x0158 -#define SNB_LINK_STATUS_OFFSET 0x01A2 -#define SNB_PCICMD_OFFSET 0x0504 -#define SNB_DEVCTRL_OFFSET 0x0598 -#define SNB_DEVSTS_OFFSET 0x059A -#define SNB_SLINK_STATUS_OFFSET 0x05A2 - -#define SNB_PBAR2LMT_OFFSET 0x0000 -#define SNB_PBAR4LMT_OFFSET 0x0008 -#define SNB_PBAR5LMT_OFFSET 0x000C -#define SNB_PBAR2XLAT_OFFSET 0x0010 -#define SNB_PBAR4XLAT_OFFSET 0x0018 -#define SNB_PBAR5XLAT_OFFSET 0x001C -#define SNB_SBAR2LMT_OFFSET 0x0020 -#define SNB_SBAR4LMT_OFFSET 0x0028 -#define SNB_SBAR5LMT_OFFSET 0x002C -#define SNB_SBAR2XLAT_OFFSET 0x0030 -#define SNB_SBAR4XLAT_OFFSET 0x0038 -#define SNB_SBAR5XLAT_OFFSET 0x003C -#define SNB_SBAR0BASE_OFFSET 0x0040 -#define SNB_SBAR2BASE_OFFSET 0x0048 -#define SNB_SBAR4BASE_OFFSET 0x0050 -#define SNB_SBAR5BASE_OFFSET 0x0054 -#define SNB_NTBCNTL_OFFSET 0x0058 -#define SNB_SBDF_OFFSET 0x005C -#define SNB_PDOORBELL_OFFSET 0x0060 -#define SNB_PDBMSK_OFFSET 0x0062 -#define SNB_SDOORBELL_OFFSET 0x0064 -#define SNB_SDBMSK_OFFSET 0x0066 -#define SNB_USMEMMISS_OFFSET 0x0070 -#define SNB_SPAD_OFFSET 0x0080 -#define SNB_SPADSEMA4_OFFSET 0x00c0 -#define SNB_WCCNTRL_OFFSET 0x00e0 -#define SNB_B2B_SPAD_OFFSET 0x0100 -#define SNB_B2B_DOORBELL_OFFSET 0x0140 -#define SNB_B2B_XLAT_OFFSETL 0x0144 -#define SNB_B2B_XLAT_OFFSETU 0x0148 -/* - * The addresses are setup so the 32bit BARs can function. Thus - * the addresses are all in 32bit space - */ -#define SNB_MBAR01_USD_ADDR 0x000000002100000CULL -#define SNB_MBAR23_USD_ADDR 0x000000004100000CULL -#define SNB_MBAR4_USD_ADDR 0x000000008100000CULL -#define SNB_MBAR5_USD_ADDR 0x00000000A100000CULL -#define SNB_MBAR01_DSD_ADDR 0x000000002000000CULL -#define SNB_MBAR23_DSD_ADDR 0x000000004000000CULL -#define SNB_MBAR4_DSD_ADDR 0x000000008000000CULL -#define SNB_MBAR5_DSD_ADDR 0x00000000A000000CULL - -#define BWD_MSIX_CNT 34 -#define BWD_MAX_SPADS 16 -#define BWD_MAX_DB_BITS 34 -#define BWD_DB_BITS_PER_VEC 1 -#define BWD_MAX_MW 2 - -#define BWD_PCICMD_OFFSET 0xb004 -#define BWD_MBAR23_OFFSET 0xb018 -#define BWD_MBAR45_OFFSET 0xb020 -#define BWD_DEVCTRL_OFFSET 0xb048 -#define BWD_LINK_STATUS_OFFSET 0xb052 -#define BWD_ERRCORSTS_OFFSET 0xb110 - -#define BWD_SBAR2XLAT_OFFSET 0x0008 -#define BWD_SBAR4XLAT_OFFSET 0x0010 -#define BWD_PDOORBELL_OFFSET 0x0020 -#define BWD_PDBMSK_OFFSET 0x0028 -#define BWD_NTBCNTL_OFFSET 0x0060 -#define BWD_EBDF_OFFSET 0x0064 -#define BWD_SPAD_OFFSET 0x0080 -#define BWD_SPADSEMA_OFFSET 0x00c0 -#define BWD_STKYSPAD_OFFSET 0x00c4 -#define BWD_PBAR2XLAT_OFFSET 0x8008 -#define BWD_PBAR4XLAT_OFFSET 0x8010 -#define BWD_B2B_DOORBELL_OFFSET 0x8020 -#define BWD_B2B_SPAD_OFFSET 0x8080 -#define BWD_B2B_SPADSEMA_OFFSET 0x80c0 -#define BWD_B2B_STKYSPAD_OFFSET 0x80c4 - -#define BWD_MODPHY_PCSREG4 0x1c004 -#define BWD_MODPHY_PCSREG6 0x1c006 - -#define BWD_IP_BASE 0xC000 -#define BWD_DESKEWSTS_OFFSET (BWD_IP_BASE + 0x3024) -#define BWD_LTSSMERRSTS0_OFFSET (BWD_IP_BASE + 0x3180) +#ifndef NTB_HW_INTEL_H +#define NTB_HW_INTEL_H + +#include +#include + +#define PCI_DEVICE_ID_INTEL_NTB_B2B_JSF 0x3725 +#define PCI_DEVICE_ID_INTEL_NTB_PS_JSF 0x3726 +#define PCI_DEVICE_ID_INTEL_NTB_SS_JSF 0x3727 +#define PCI_DEVICE_ID_INTEL_NTB_B2B_SNB 0x3C0D +#define PCI_DEVICE_ID_INTEL_NTB_PS_SNB 0x3C0E +#define PCI_DEVICE_ID_INTEL_NTB_SS_SNB 0x3C0F +#define PCI_DEVICE_ID_INTEL_NTB_B2B_IVT 0x0E0D +#define PCI_DEVICE_ID_INTEL_NTB_PS_IVT 0x0E0E +#define PCI_DEVICE_ID_INTEL_NTB_SS_IVT 0x0E0F +#define PCI_DEVICE_ID_INTEL_NTB_B2B_HSX 0x2F0D +#define PCI_DEVICE_ID_INTEL_NTB_PS_HSX 0x2F0E +#define PCI_DEVICE_ID_INTEL_NTB_SS_HSX 0x2F0F +#define PCI_DEVICE_ID_INTEL_NTB_B2B_BWD 0x0C4E + +/* SNB hardware (and JSF, IVT, HSX) */ + +#define SNB_PBAR23LMT_OFFSET 0x0000 +#define SNB_PBAR45LMT_OFFSET 0x0008 +#define SNB_PBAR4LMT_OFFSET 0x0008 +#define SNB_PBAR5LMT_OFFSET 0x000c +#define SNB_PBAR23XLAT_OFFSET 0x0010 +#define SNB_PBAR45XLAT_OFFSET 0x0018 +#define SNB_PBAR4XLAT_OFFSET 0x0018 +#define SNB_PBAR5XLAT_OFFSET 0x001c +#define SNB_SBAR23LMT_OFFSET 0x0020 +#define SNB_SBAR45LMT_OFFSET 0x0028 +#define SNB_SBAR4LMT_OFFSET 0x0028 +#define SNB_SBAR5LMT_OFFSET 0x002c +#define SNB_SBAR23XLAT_OFFSET 0x0030 +#define SNB_SBAR45XLAT_OFFSET 0x0038 +#define SNB_SBAR4XLAT_OFFSET 0x0038 +#define SNB_SBAR5XLAT_OFFSET 0x003c +#define SNB_SBAR0BASE_OFFSET 0x0040 +#define SNB_SBAR23BASE_OFFSET 0x0048 +#define SNB_SBAR45BASE_OFFSET 0x0050 +#define SNB_SBAR4BASE_OFFSET 0x0050 +#define SNB_SBAR5BASE_OFFSET 0x0054 +#define SNB_SBDF_OFFSET 0x005c +#define SNB_NTBCNTL_OFFSET 0x0058 +#define SNB_PDOORBELL_OFFSET 0x0060 +#define SNB_PDBMSK_OFFSET 0x0062 +#define SNB_SDOORBELL_OFFSET 0x0064 +#define SNB_SDBMSK_OFFSET 0x0066 +#define SNB_USMEMMISS_OFFSET 0x0070 +#define SNB_SPAD_OFFSET 0x0080 +#define SNB_PBAR23SZ_OFFSET 0x00d0 +#define SNB_PBAR45SZ_OFFSET 0x00d1 +#define SNB_PBAR4SZ_OFFSET 0x00d1 +#define SNB_SBAR23SZ_OFFSET 0x00d2 +#define SNB_SBAR45SZ_OFFSET 0x00d3 +#define SNB_SBAR4SZ_OFFSET 0x00d3 +#define SNB_PPD_OFFSET 0x00d4 +#define SNB_PBAR5SZ_OFFSET 0x00d5 +#define SNB_SBAR5SZ_OFFSET 0x00d6 +#define SNB_WCCNTRL_OFFSET 0x00e0 +#define SNB_UNCERRSTS_OFFSET 0x014c +#define SNB_CORERRSTS_OFFSET 0x0158 +#define SNB_LINK_STATUS_OFFSET 0x01a2 +#define SNB_SPCICMD_OFFSET 0x0504 +#define SNB_DEVCTRL_OFFSET 0x0598 +#define SNB_DEVSTS_OFFSET 0x059a +#define SNB_SLINK_STATUS_OFFSET 0x05a2 +#define SNB_B2B_SPAD_OFFSET 0x0100 +#define SNB_B2B_DOORBELL_OFFSET 0x0140 +#define SNB_B2B_XLAT_OFFSETL 0x0144 +#define SNB_B2B_XLAT_OFFSETU 0x0148 +#define SNB_PPD_CONN_MASK 0x03 +#define SNB_PPD_CONN_TRANSPARENT 0x00 +#define SNB_PPD_CONN_B2B 0x01 +#define SNB_PPD_CONN_RP 0x02 +#define SNB_PPD_DEV_MASK 0x10 +#define SNB_PPD_DEV_USD 0x00 +#define SNB_PPD_DEV_DSD 0x10 +#define SNB_PPD_SPLIT_BAR_MASK 0x40 + +#define SNB_PPD_TOPO_MASK (SNB_PPD_CONN_MASK | SNB_PPD_DEV_MASK) +#define SNB_PPD_TOPO_PRI_USD (SNB_PPD_CONN_RP | SNB_PPD_DEV_USD) +#define SNB_PPD_TOPO_PRI_DSD (SNB_PPD_CONN_RP | SNB_PPD_DEV_DSD) +#define SNB_PPD_TOPO_SEC_USD (SNB_PPD_CONN_TRANSPARENT | SNB_PPD_DEV_USD) +#define SNB_PPD_TOPO_SEC_DSD (SNB_PPD_CONN_TRANSPARENT | SNB_PPD_DEV_DSD) +#define SNB_PPD_TOPO_B2B_USD (SNB_PPD_CONN_B2B | SNB_PPD_DEV_USD) +#define SNB_PPD_TOPO_B2B_DSD (SNB_PPD_CONN_B2B | SNB_PPD_DEV_DSD) + +#define SNB_MW_COUNT 2 +#define HSX_SPLIT_BAR_MW_COUNT 3 +#define SNB_DB_COUNT 15 +#define SNB_DB_LINK 15 +#define SNB_DB_LINK_BIT BIT_ULL(SNB_DB_LINK) +#define SNB_DB_MSIX_VECTOR_COUNT 4 +#define SNB_DB_MSIX_VECTOR_SHIFT 5 +#define SNB_DB_TOTAL_SHIFT 16 +#define SNB_SPAD_COUNT 16 + +/* BWD hardware */ + +#define BWD_SBAR2XLAT_OFFSET 0x0008 +#define BWD_PDOORBELL_OFFSET 0x0020 +#define BWD_PDBMSK_OFFSET 0x0028 +#define BWD_NTBCNTL_OFFSET 0x0060 +#define BWD_SPAD_OFFSET 0x0080 +#define BWD_PPD_OFFSET 0x00d4 +#define BWD_PBAR2XLAT_OFFSET 0x8008 +#define BWD_B2B_DOORBELL_OFFSET 0x8020 +#define BWD_B2B_SPAD_OFFSET 0x8080 +#define BWD_SPCICMD_OFFSET 0xb004 +#define BWD_LINK_STATUS_OFFSET 0xb052 +#define BWD_ERRCORSTS_OFFSET 0xb110 +#define BWD_IP_BASE 0xc000 +#define BWD_DESKEWSTS_OFFSET (BWD_IP_BASE + 0x3024) +#define BWD_LTSSMERRSTS0_OFFSET (BWD_IP_BASE + 0x3180) #define BWD_LTSSMSTATEJMP_OFFSET (BWD_IP_BASE + 0x3040) #define BWD_IBSTERRRCRVSTS0_OFFSET (BWD_IP_BASE + 0x3324) +#define BWD_MODPHY_PCSREG4 0x1c004 +#define BWD_MODPHY_PCSREG6 0x1c006 + +#define BWD_PPD_INIT_LINK 0x0008 +#define BWD_PPD_CONN_MASK 0x0300 +#define BWD_PPD_CONN_TRANSPARENT 0x0000 +#define BWD_PPD_CONN_B2B 0x0100 +#define BWD_PPD_CONN_RP 0x0200 +#define BWD_PPD_DEV_MASK 0x1000 +#define BWD_PPD_DEV_USD 0x0000 +#define BWD_PPD_DEV_DSD 0x1000 +#define BWD_PPD_TOPO_MASK (BWD_PPD_CONN_MASK | BWD_PPD_DEV_MASK) +#define BWD_PPD_TOPO_PRI_USD (BWD_PPD_CONN_TRANSPARENT | BWD_PPD_DEV_USD) +#define BWD_PPD_TOPO_PRI_DSD (BWD_PPD_CONN_TRANSPARENT | BWD_PPD_DEV_DSD) +#define BWD_PPD_TOPO_SEC_USD (BWD_PPD_CONN_RP | BWD_PPD_DEV_USD) +#define BWD_PPD_TOPO_SEC_DSD (BWD_PPD_CONN_RP | BWD_PPD_DEV_DSD) +#define BWD_PPD_TOPO_B2B_USD (BWD_PPD_CONN_B2B | BWD_PPD_DEV_USD) +#define BWD_PPD_TOPO_B2B_DSD (BWD_PPD_CONN_B2B | BWD_PPD_DEV_DSD) + +#define BWD_MW_COUNT 2 +#define BWD_DB_COUNT 34 +#define BWD_DB_VALID_MASK (BIT_ULL(BWD_DB_COUNT) - 1) +#define BWD_DB_MSIX_VECTOR_COUNT 34 +#define BWD_DB_MSIX_VECTOR_SHIFT 1 +#define BWD_DB_TOTAL_SHIFT 34 +#define BWD_SPAD_COUNT 16 + +#define BWD_NTB_CTL_DOWN_BIT BIT(16) +#define BWD_NTB_CTL_ACTIVE(x) !(x & BWD_NTB_CTL_DOWN_BIT) + +#define BWD_DESKEWSTS_DBERR BIT(15) +#define BWD_LTSSMERRSTS0_UNEXPECTEDEI BIT(20) +#define BWD_LTSSMSTATEJMP_FORCEDETECT BIT(2) +#define BWD_IBIST_ERR_OFLOW 0x7FFF7FFF + +#define BWD_LINK_HB_TIMEOUT msecs_to_jiffies(1000) +#define BWD_LINK_RECOVERY_TIME msecs_to_jiffies(500) + +/* Ntb control and link status */ + +#define NTB_CTL_CFG_LOCK BIT(0) +#define NTB_CTL_DISABLE BIT(1) +#define NTB_CTL_S2P_BAR2_SNOOP BIT(2) +#define NTB_CTL_P2S_BAR2_SNOOP BIT(4) +#define NTB_CTL_S2P_BAR4_SNOOP BIT(6) +#define NTB_CTL_P2S_BAR4_SNOOP BIT(8) +#define NTB_CTL_S2P_BAR5_SNOOP BIT(12) +#define NTB_CTL_P2S_BAR5_SNOOP BIT(14) + +#define NTB_LNK_STA_ACTIVE_BIT 0x2000 +#define NTB_LNK_STA_SPEED_MASK 0x000f +#define NTB_LNK_STA_WIDTH_MASK 0x03f0 +#define NTB_LNK_STA_ACTIVE(x) (!!((x) & NTB_LNK_STA_ACTIVE_BIT)) +#define NTB_LNK_STA_SPEED(x) ((x) & NTB_LNK_STA_SPEED_MASK) +#define NTB_LNK_STA_WIDTH(x) (((x) & NTB_LNK_STA_WIDTH_MASK) >> 4) + +/* Use the following addresses for translation between b2b ntb devices in case + * the hardware default values are not reliable. */ +#define SNB_B2B_BAR0_USD_ADDR 0x1000000000000000ull +#define SNB_B2B_BAR2_USD_ADDR64 0x2000000000000000ull +#define SNB_B2B_BAR4_USD_ADDR64 0x4000000000000000ull +#define SNB_B2B_BAR4_USD_ADDR32 0x20000000u +#define SNB_B2B_BAR5_USD_ADDR32 0x40000000u +#define SNB_B2B_BAR0_DSD_ADDR 0x9000000000000000ull +#define SNB_B2B_BAR2_DSD_ADDR64 0xa000000000000000ull +#define SNB_B2B_BAR4_DSD_ADDR64 0xc000000000000000ull +#define SNB_B2B_BAR4_DSD_ADDR32 0xa0000000u +#define SNB_B2B_BAR5_DSD_ADDR32 0xc0000000u + +/* The peer ntb secondary config space is 32KB fixed size */ +#define SNB_B2B_MIN_SIZE 0x8000 + +/* flags to indicate hardware errata */ +#define NTB_HWERR_SDOORBELL_LOCKUP BIT_ULL(0) +#define NTB_HWERR_SB01BASE_LOCKUP BIT_ULL(1) +#define NTB_HWERR_B2BDOORBELL_BIT14 BIT_ULL(2) + +/* flags to indicate unsafe api */ +#define NTB_UNSAFE_DB BIT_ULL(0) +#define NTB_UNSAFE_SPAD BIT_ULL(1) + +struct intel_ntb_dev; + +struct intel_ntb_reg { + int (*poll_link)(struct intel_ntb_dev *ndev); + int (*link_is_up)(struct intel_ntb_dev *ndev); + u64 (*db_ioread)(void __iomem *mmio); + void (*db_iowrite)(u64 db_bits, void __iomem *mmio); + unsigned long ntb_ctl; + resource_size_t db_size; + int mw_bar[]; +}; -#define BWD_DESKEWSTS_DBERR (1 << 15) -#define BWD_LTSSMERRSTS0_UNEXPECTEDEI (1 << 20) -#define BWD_LTSSMSTATEJMP_FORCEDETECT (1 << 2) -#define BWD_IBIST_ERR_OFLOW 0x7FFF7FFF - -#define NTB_CNTL_CFG_LOCK (1 << 0) -#define NTB_CNTL_LINK_DISABLE (1 << 1) -#define NTB_CNTL_S2P_BAR23_SNOOP (1 << 2) -#define NTB_CNTL_P2S_BAR23_SNOOP (1 << 4) -#define NTB_CNTL_S2P_BAR4_SNOOP (1 << 6) -#define NTB_CNTL_P2S_BAR4_SNOOP (1 << 8) -#define NTB_CNTL_S2P_BAR5_SNOOP (1 << 12) -#define NTB_CNTL_P2S_BAR5_SNOOP (1 << 14) -#define BWD_CNTL_LINK_DOWN (1 << 16) - -#define NTB_PPD_OFFSET 0x00D4 -#define SNB_PPD_CONN_TYPE 0x0003 -#define SNB_PPD_DEV_TYPE 0x0010 -#define SNB_PPD_SPLIT_BAR (1 << 6) -#define BWD_PPD_INIT_LINK 0x0008 -#define BWD_PPD_CONN_TYPE 0x0300 -#define BWD_PPD_DEV_TYPE 0x1000 -#define PCI_DEVICE_ID_INTEL_NTB_B2B_JSF 0x3725 -#define PCI_DEVICE_ID_INTEL_NTB_PS_JSF 0x3726 -#define PCI_DEVICE_ID_INTEL_NTB_SS_JSF 0x3727 -#define PCI_DEVICE_ID_INTEL_NTB_B2B_SNB 0x3C0D -#define PCI_DEVICE_ID_INTEL_NTB_PS_SNB 0x3C0E -#define PCI_DEVICE_ID_INTEL_NTB_SS_SNB 0x3C0F -#define PCI_DEVICE_ID_INTEL_NTB_B2B_IVT 0x0E0D -#define PCI_DEVICE_ID_INTEL_NTB_PS_IVT 0x0E0E -#define PCI_DEVICE_ID_INTEL_NTB_SS_IVT 0x0E0F -#define PCI_DEVICE_ID_INTEL_NTB_B2B_HSX 0x2F0D -#define PCI_DEVICE_ID_INTEL_NTB_PS_HSX 0x2F0E -#define PCI_DEVICE_ID_INTEL_NTB_SS_HSX 0x2F0F -#define PCI_DEVICE_ID_INTEL_NTB_B2B_BWD 0x0C4E - -#ifndef readq -static inline u64 readq(void __iomem *addr) -{ - return readl(addr) | (((u64) readl(addr + 4)) << 32LL); -} -#endif - -#ifndef writeq -static inline void writeq(u64 val, void __iomem *addr) -{ - writel(val & 0xffffffff, addr); - writel(val >> 32, addr + 4); -} -#endif +struct intel_ntb_alt_reg { + unsigned long db_bell; + unsigned long db_mask; + unsigned long spad; +}; -#define NTB_BAR_MMIO 0 -#define NTB_BAR_23 2 -#define NTB_BAR_4 4 -#define NTB_BAR_5 5 - -#define NTB_BAR_MASK ((1 << NTB_BAR_MMIO) | (1 << NTB_BAR_23) |\ - (1 << NTB_BAR_4)) -#define NTB_SPLITBAR_MASK ((1 << NTB_BAR_MMIO) | (1 << NTB_BAR_23) |\ - (1 << NTB_BAR_4) | (1 << NTB_BAR_5)) - -#define NTB_HB_TIMEOUT msecs_to_jiffies(1000) - -enum ntb_hw_event { - NTB_EVENT_SW_EVENT0 = 0, - NTB_EVENT_SW_EVENT1, - NTB_EVENT_SW_EVENT2, - NTB_EVENT_HW_ERROR, - NTB_EVENT_HW_LINK_UP, - NTB_EVENT_HW_LINK_DOWN, +struct intel_ntb_xlat_reg { + unsigned long bar0_base; + unsigned long bar2_xlat; + unsigned long bar2_limit; }; -struct ntb_mw { - dma_addr_t phys_addr; - void __iomem *vbase; - resource_size_t bar_sz; +struct intel_b2b_addr { + phys_addr_t bar0_addr; + phys_addr_t bar2_addr64; + phys_addr_t bar4_addr64; + phys_addr_t bar4_addr32; + phys_addr_t bar5_addr32; }; -struct ntb_db_cb { - int (*callback)(void *data, int db_num); - unsigned int db_num; - void *data; - struct ntb_device *ndev; - struct tasklet_struct irq_work; +struct intel_ntb_vec { + struct intel_ntb_dev *ndev; + int num; }; -#define WA_SNB_ERR 0x00000001 - -struct ntb_device { - struct pci_dev *pdev; - struct msix_entry *msix_entries; - void __iomem *reg_base; - struct ntb_mw *mw; - struct { - unsigned char max_mw; - unsigned char max_spads; - unsigned char max_db_bits; - unsigned char msix_cnt; - } limits; - struct { - void __iomem *ldb; - void __iomem *ldb_mask; - void __iomem *rdb; - void __iomem *bar2_xlat; - void __iomem *bar4_xlat; - void __iomem *bar5_xlat; - void __iomem *spad_write; - void __iomem *spad_read; - void __iomem *lnk_cntl; - void __iomem *lnk_stat; - void __iomem *spci_cmd; - } reg_ofs; - struct ntb_transport *ntb_transport; - void (*event_cb)(void *handle, enum ntb_hw_event event); - - struct ntb_db_cb *db_cb; - unsigned char hw_type; - unsigned char conn_type; - unsigned char dev_type; - unsigned char num_msix; - unsigned char bits_per_vector; - unsigned char max_cbs; - unsigned char link_width; - unsigned char link_speed; - unsigned char link_status; - unsigned char split_bar; - - struct delayed_work hb_timer; - unsigned long last_ts; - - struct delayed_work lr_timer; - - struct dentry *debugfs_dir; - struct dentry *debugfs_info; - - unsigned int wa_flags; +struct intel_ntb_dev { + struct ntb_dev ntb; + + /* offset of peer bar0 in b2b bar */ + unsigned long b2b_off; + /* mw idx used to access peer bar0 */ + unsigned int b2b_idx; + + /* BAR45 is split into BAR4 and BAR5 */ + bool bar4_split; + + u32 ntb_ctl; + u32 lnk_sta; + + unsigned char mw_count; + unsigned char spad_count; + unsigned char db_count; + unsigned char db_vec_count; + unsigned char db_vec_shift; + + u64 db_valid_mask; + u64 db_link_mask; + u64 db_mask; + + /* synchronize rmw access of db_mask and hw reg */ + spinlock_t db_mask_lock; + + struct msix_entry *msix; + struct intel_ntb_vec *vec; + + const struct intel_ntb_reg *reg; + const struct intel_ntb_alt_reg *self_reg; + const struct intel_ntb_alt_reg *peer_reg; + const struct intel_ntb_xlat_reg *xlat_reg; + void __iomem *self_mmio; + void __iomem *peer_mmio; + phys_addr_t peer_addr; + + unsigned long last_ts; + struct delayed_work hb_timer; + + unsigned long hwerr_flags; + unsigned long unsafe_flags; + unsigned long unsafe_flags_ignore; + + struct dentry *debugfs_dir; + struct dentry *debugfs_info; }; -/** - * ntb_max_cbs() - return the max callbacks - * @ndev: pointer to ntb_device instance - * - * Given the ntb pointer, return the maximum number of callbacks - * - * RETURNS: the maximum number of callbacks - */ -static inline unsigned char ntb_max_cbs(struct ntb_device *ndev) -{ - return ndev->max_cbs; -} - -/** - * ntb_max_mw() - return the max number of memory windows - * @ndev: pointer to ntb_device instance - * - * Given the ntb pointer, return the maximum number of memory windows - * - * RETURNS: the maximum number of memory windows - */ -static inline unsigned char ntb_max_mw(struct ntb_device *ndev) -{ - return ndev->limits.max_mw; -} - -/** - * ntb_hw_link_status() - return the hardware link status - * @ndev: pointer to ntb_device instance - * - * Returns true if the hardware is connected to the remote system - * - * RETURNS: true or false based on the hardware link state - */ -static inline bool ntb_hw_link_status(struct ntb_device *ndev) -{ - return ndev->link_status == NTB_LINK_UP; -} - -/** - * ntb_query_pdev() - return the pci_dev pointer - * @ndev: pointer to ntb_device instance - * - * Given the ntb pointer, return the pci_dev pointer for the NTB hardware device - * - * RETURNS: a pointer to the ntb pci_dev - */ -static inline struct pci_dev *ntb_query_pdev(struct ntb_device *ndev) -{ - return ndev->pdev; -} - -/** - * ntb_query_debugfs() - return the debugfs pointer - * @ndev: pointer to ntb_device instance - * - * Given the ntb pointer, return the debugfs directory pointer for the NTB - * hardware device - * - * RETURNS: a pointer to the debugfs directory - */ -static inline struct dentry *ntb_query_debugfs(struct ntb_device *ndev) -{ - return ndev->debugfs_dir; -} - -struct ntb_device *ntb_register_transport(struct pci_dev *pdev, - void *transport); -void ntb_unregister_transport(struct ntb_device *ndev); -void ntb_set_mw_addr(struct ntb_device *ndev, unsigned int mw, u64 addr); -int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx, - void *data, int (*db_cb_func)(void *data, - int db_num)); -void ntb_unregister_db_callback(struct ntb_device *ndev, unsigned int idx); -int ntb_register_event_callback(struct ntb_device *ndev, - void (*event_cb_func)(void *handle, - enum ntb_hw_event event)); -void ntb_unregister_event_callback(struct ntb_device *ndev); -int ntb_get_max_spads(struct ntb_device *ndev); -int ntb_write_local_spad(struct ntb_device *ndev, unsigned int idx, u32 val); -int ntb_read_local_spad(struct ntb_device *ndev, unsigned int idx, u32 *val); -int ntb_write_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 val); -int ntb_read_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 *val); -resource_size_t ntb_get_mw_base(struct ntb_device *ndev, unsigned int mw); -void __iomem *ntb_get_mw_vbase(struct ntb_device *ndev, unsigned int mw); -u64 ntb_get_mw_size(struct ntb_device *ndev, unsigned int mw); -void ntb_ring_doorbell(struct ntb_device *ndev, unsigned int idx); -void *ntb_find_transport(struct pci_dev *pdev); - -int ntb_transport_init(struct pci_dev *pdev); -void ntb_transport_free(void *transport); +#define ndev_pdev(ndev) ((ndev)->ntb.pdev) +#define ndev_name(ndev) pci_name(ndev_pdev(ndev)) +#define ndev_dev(ndev) (&ndev_pdev(ndev)->dev) +#define ntb_ndev(ntb) container_of(ntb, struct intel_ntb_dev, ntb) +#define hb_ndev(work) container_of(work, struct intel_ntb_dev, hb_timer.work) + +#endif diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index c5f26cda9f97..9faf1c6029af 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c @@ -5,6 +5,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 Intel Corporation. All rights reserved. + * Copyright (C) 2015 EMC Corporation. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -13,6 +14,7 @@ * BSD LICENSE * * Copyright(c) 2012 Intel Corporation. All rights reserved. + * Copyright (C) 2015 EMC Corporation. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -40,7 +42,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Intel PCIe NTB Linux driver + * PCIe NTB Transport Linux driver * * Contact Information: * Jon Mason @@ -56,9 +58,22 @@ #include #include #include -#include "hw/intel/ntb_hw_intel.h" +#include "linux/ntb.h" +#include "linux/ntb_transport.h" -#define NTB_TRANSPORT_VERSION 3 +#define NTB_TRANSPORT_VERSION 4 +#define NTB_TRANSPORT_VER "4" +#define NTB_TRANSPORT_NAME "ntb_transport" +#define NTB_TRANSPORT_DESC "Software Queue-Pair Transport over NTB" + +MODULE_DESCRIPTION(NTB_TRANSPORT_DESC); +MODULE_VERSION(NTB_TRANSPORT_VER); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("Intel Corporation"); + +static unsigned long max_mw_size; +module_param(max_mw_size, ulong, 0644); +MODULE_PARM_DESC(max_mw_size, "Limit size of large memory windows"); static unsigned int transport_mtu = 0x401E; module_param(transport_mtu, uint, 0644); @@ -72,10 +87,12 @@ static unsigned int copy_bytes = 1024; module_param(copy_bytes, uint, 0644); MODULE_PARM_DESC(copy_bytes, "Threshold under which NTB will use the CPU to copy instead of DMA"); +static struct dentry *nt_debugfs_dir; + struct ntb_queue_entry { /* ntb_queue list reference */ struct list_head entry; - /* pointers to data to be transfered */ + /* pointers to data to be transferred */ void *cb_data; void *buf; unsigned int len; @@ -94,14 +111,16 @@ struct ntb_rx_info { }; struct ntb_transport_qp { - struct ntb_transport *transport; - struct ntb_device *ndev; + struct ntb_transport_ctx *transport; + struct ntb_dev *ndev; void *cb_data; struct dma_chan *dma_chan; bool client_ready; - bool qp_link; + bool link_is_up; + u8 qp_num; /* Only 64 QP's are allowed. 0-63 */ + u64 qp_bit; struct ntb_rx_info __iomem *rx_info; struct ntb_rx_info *remote_rx_info; @@ -127,6 +146,7 @@ struct ntb_transport_qp { unsigned int rx_max_entry; unsigned int rx_max_frame; dma_cookie_t last_cookie; + struct tasklet_struct rxc_db_work; void (*event_handler)(void *data, int status); struct delayed_work link_work; @@ -153,33 +173,44 @@ struct ntb_transport_qp { }; struct ntb_transport_mw { - size_t size; + phys_addr_t phys_addr; + resource_size_t phys_size; + resource_size_t xlat_align; + resource_size_t xlat_align_size; + void __iomem *vbase; + size_t xlat_size; + size_t buff_size; void *virt_addr; dma_addr_t dma_addr; }; struct ntb_transport_client_dev { struct list_head entry; + struct ntb_transport_ctx *nt; struct device dev; }; -struct ntb_transport { +struct ntb_transport_ctx { struct list_head entry; struct list_head client_devs; - struct ntb_device *ndev; - struct ntb_transport_mw *mw; - struct ntb_transport_qp *qps; - unsigned int max_qps; - unsigned long qp_bitmap; - bool transport_link; + struct ntb_dev *ndev; + + struct ntb_transport_mw *mw_vec; + struct ntb_transport_qp *qp_vec; + unsigned int mw_count; + unsigned int qp_count; + u64 qp_bitmap; + u64 qp_bitmap_free; + + bool link_is_up; struct delayed_work link_work; struct work_struct link_cleanup; }; enum { - DESC_DONE_FLAG = 1 << 0, - LINK_DOWN_FLAG = 1 << 1, + DESC_DONE_FLAG = BIT(0), + LINK_DOWN_FLAG = BIT(1), }; struct ntb_payload_header { @@ -200,68 +231,69 @@ enum { MAX_SPAD, }; -#define QP_TO_MW(ndev, qp) ((qp) % ntb_max_mw(ndev)) +#define dev_client_dev(__dev) \ + container_of((__dev), struct ntb_transport_client_dev, dev) + +#define drv_client(__drv) \ + container_of((__drv), struct ntb_transport_client, driver) + +#define QP_TO_MW(nt, qp) ((qp) % nt->mw_count) #define NTB_QP_DEF_NUM_ENTRIES 100 #define NTB_LINK_DOWN_TIMEOUT 10 -static int ntb_match_bus(struct device *dev, struct device_driver *drv) +static void ntb_transport_rxc_db(unsigned long data); +static const struct ntb_ctx_ops ntb_transport_ops; +static struct ntb_client ntb_transport_client; + +static int ntb_transport_bus_match(struct device *dev, + struct device_driver *drv) { return !strncmp(dev_name(dev), drv->name, strlen(drv->name)); } -static int ntb_client_probe(struct device *dev) +static int ntb_transport_bus_probe(struct device *dev) { - const struct ntb_client *drv = container_of(dev->driver, - struct ntb_client, driver); - struct pci_dev *pdev = container_of(dev->parent, struct pci_dev, dev); + const struct ntb_transport_client *client; int rc = -EINVAL; get_device(dev); - if (drv && drv->probe) - rc = drv->probe(pdev); + + client = drv_client(dev->driver); + rc = client->probe(dev); if (rc) put_device(dev); return rc; } -static int ntb_client_remove(struct device *dev) +static int ntb_transport_bus_remove(struct device *dev) { - const struct ntb_client *drv = container_of(dev->driver, - struct ntb_client, driver); - struct pci_dev *pdev = container_of(dev->parent, struct pci_dev, dev); + const struct ntb_transport_client *client; - if (drv && drv->remove) - drv->remove(pdev); + client = drv_client(dev->driver); + client->remove(dev); put_device(dev); return 0; } -static struct bus_type ntb_bus_type = { - .name = "ntb_bus", - .match = ntb_match_bus, - .probe = ntb_client_probe, - .remove = ntb_client_remove, +static struct bus_type ntb_transport_bus = { + .name = "ntb_transport", + .match = ntb_transport_bus_match, + .probe = ntb_transport_bus_probe, + .remove = ntb_transport_bus_remove, }; static LIST_HEAD(ntb_transport_list); -static int ntb_bus_init(struct ntb_transport *nt) +static int ntb_bus_init(struct ntb_transport_ctx *nt) { - if (list_empty(&ntb_transport_list)) { - int rc = bus_register(&ntb_bus_type); - if (rc) - return rc; - } - list_add(&nt->entry, &ntb_transport_list); - return 0; } -static void ntb_bus_remove(struct ntb_transport *nt) +static void ntb_bus_remove(struct ntb_transport_ctx *nt) { struct ntb_transport_client_dev *client_dev, *cd; @@ -273,29 +305,26 @@ static void ntb_bus_remove(struct ntb_transport *nt) } list_del(&nt->entry); - - if (list_empty(&ntb_transport_list)) - bus_unregister(&ntb_bus_type); } -static void ntb_client_release(struct device *dev) +static void ntb_transport_client_release(struct device *dev) { struct ntb_transport_client_dev *client_dev; - client_dev = container_of(dev, struct ntb_transport_client_dev, dev); + client_dev = dev_client_dev(dev); kfree(client_dev); } /** - * ntb_unregister_client_dev - Unregister NTB client device + * ntb_transport_unregister_client_dev - Unregister NTB client device * @device_name: Name of NTB client device * * Unregister an NTB client device with the NTB transport layer */ -void ntb_unregister_client_dev(char *device_name) +void ntb_transport_unregister_client_dev(char *device_name) { struct ntb_transport_client_dev *client, *cd; - struct ntb_transport *nt; + struct ntb_transport_ctx *nt; list_for_each_entry(nt, &ntb_transport_list, entry) list_for_each_entry_safe(client, cd, &nt->client_devs, entry) @@ -305,18 +334,18 @@ void ntb_unregister_client_dev(char *device_name) device_unregister(&client->dev); } } -EXPORT_SYMBOL_GPL(ntb_unregister_client_dev); +EXPORT_SYMBOL_GPL(ntb_transport_unregister_client_dev); /** - * ntb_register_client_dev - Register NTB client device + * ntb_transport_register_client_dev - Register NTB client device * @device_name: Name of NTB client device * * Register an NTB client device with the NTB transport layer */ -int ntb_register_client_dev(char *device_name) +int ntb_transport_register_client_dev(char *device_name) { struct ntb_transport_client_dev *client_dev; - struct ntb_transport *nt; + struct ntb_transport_ctx *nt; int rc, i = 0; if (list_empty(&ntb_transport_list)) @@ -325,7 +354,7 @@ int ntb_register_client_dev(char *device_name) list_for_each_entry(nt, &ntb_transport_list, entry) { struct device *dev; - client_dev = kzalloc(sizeof(struct ntb_transport_client_dev), + client_dev = kzalloc(sizeof(*client_dev), GFP_KERNEL); if (!client_dev) { rc = -ENOMEM; @@ -336,9 +365,9 @@ int ntb_register_client_dev(char *device_name) /* setup and register client devices */ dev_set_name(dev, "%s%d", device_name, i); - dev->bus = &ntb_bus_type; - dev->release = ntb_client_release; - dev->parent = &ntb_query_pdev(nt->ndev)->dev; + dev->bus = &ntb_transport_bus; + dev->release = ntb_transport_client_release; + dev->parent = &nt->ndev->dev; rc = device_register(dev); if (rc) { @@ -353,11 +382,11 @@ int ntb_register_client_dev(char *device_name) return 0; err: - ntb_unregister_client_dev(device_name); + ntb_transport_unregister_client_dev(device_name); return rc; } -EXPORT_SYMBOL_GPL(ntb_register_client_dev); +EXPORT_SYMBOL_GPL(ntb_transport_register_client_dev); /** * ntb_transport_register_client - Register NTB client driver @@ -367,9 +396,9 @@ EXPORT_SYMBOL_GPL(ntb_register_client_dev); * * RETURNS: An appropriate -ERRNO error value on error, or zero for success. */ -int ntb_transport_register_client(struct ntb_client *drv) +int ntb_transport_register_client(struct ntb_transport_client *drv) { - drv->driver.bus = &ntb_bus_type; + drv->driver.bus = &ntb_transport_bus; if (list_empty(&ntb_transport_list)) return -ENODEV; @@ -386,7 +415,7 @@ EXPORT_SYMBOL_GPL(ntb_transport_register_client); * * RETURNS: An appropriate -ERRNO error value on error, or zero for success. */ -void ntb_transport_unregister_client(struct ntb_client *drv) +void ntb_transport_unregister_client(struct ntb_transport_client *drv) { driver_unregister(&drv->driver); } @@ -452,8 +481,8 @@ static ssize_t debugfs_read(struct file *filp, char __user *ubuf, size_t count, "tx_max_entry - \t%u\n", qp->tx_max_entry); out_offset += snprintf(buf + out_offset, out_count - out_offset, - "\nQP Link %s\n", (qp->qp_link == NTB_LINK_UP) ? - "Up" : "Down"); + "\nQP Link %s\n", + qp->link_is_up ? "Up" : "Down"); if (out_offset > out_count) out_offset = out_count; @@ -497,26 +526,31 @@ out: return entry; } -static void ntb_transport_setup_qp_mw(struct ntb_transport *nt, - unsigned int qp_num) +static int ntb_transport_setup_qp_mw(struct ntb_transport_ctx *nt, + unsigned int qp_num) { - struct ntb_transport_qp *qp = &nt->qps[qp_num]; + struct ntb_transport_qp *qp = &nt->qp_vec[qp_num]; + struct ntb_transport_mw *mw; unsigned int rx_size, num_qps_mw; - u8 mw_num, mw_max; + unsigned int mw_num, mw_count, qp_count; unsigned int i; - mw_max = ntb_max_mw(nt->ndev); - mw_num = QP_TO_MW(nt->ndev, qp_num); + mw_count = nt->mw_count; + qp_count = nt->qp_count; - WARN_ON(nt->mw[mw_num].virt_addr == NULL); + mw_num = QP_TO_MW(nt, qp_num); + mw = &nt->mw_vec[mw_num]; + + if (!mw->virt_addr) + return -ENOMEM; - if (nt->max_qps % mw_max && mw_num + 1 < nt->max_qps / mw_max) - num_qps_mw = nt->max_qps / mw_max + 1; + if (qp_count % mw_count && mw_num + 1 < qp_count / mw_count) + num_qps_mw = qp_count / mw_count + 1; else - num_qps_mw = nt->max_qps / mw_max; + num_qps_mw = qp_count / mw_count; - rx_size = (unsigned int) nt->mw[mw_num].size / num_qps_mw; - qp->rx_buff = nt->mw[mw_num].virt_addr + qp_num / mw_max * rx_size; + rx_size = (unsigned int)mw->xlat_size / num_qps_mw; + qp->rx_buff = mw->virt_addr + rx_size * qp_num / mw_count; rx_size -= sizeof(struct ntb_rx_info); qp->remote_rx_info = qp->rx_buff + rx_size; @@ -530,49 +564,63 @@ static void ntb_transport_setup_qp_mw(struct ntb_transport *nt, /* setup the hdr offsets with 0's */ for (i = 0; i < qp->rx_max_entry; i++) { - void *offset = qp->rx_buff + qp->rx_max_frame * (i + 1) - - sizeof(struct ntb_payload_header); + void *offset = (qp->rx_buff + qp->rx_max_frame * (i + 1) - + sizeof(struct ntb_payload_header)); memset(offset, 0, sizeof(struct ntb_payload_header)); } qp->rx_pkts = 0; qp->tx_pkts = 0; qp->tx_index = 0; + + return 0; } -static void ntb_free_mw(struct ntb_transport *nt, int num_mw) +static void ntb_free_mw(struct ntb_transport_ctx *nt, int num_mw) { - struct ntb_transport_mw *mw = &nt->mw[num_mw]; - struct pci_dev *pdev = ntb_query_pdev(nt->ndev); + struct ntb_transport_mw *mw = &nt->mw_vec[num_mw]; + struct pci_dev *pdev = nt->ndev->pdev; if (!mw->virt_addr) return; - dma_free_coherent(&pdev->dev, mw->size, mw->virt_addr, mw->dma_addr); + ntb_mw_clear_trans(nt->ndev, num_mw); + dma_free_coherent(&pdev->dev, mw->buff_size, + mw->virt_addr, mw->dma_addr); + mw->xlat_size = 0; + mw->buff_size = 0; mw->virt_addr = NULL; } -static int ntb_set_mw(struct ntb_transport *nt, int num_mw, unsigned int size) +static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw, + unsigned int size) { - struct ntb_transport_mw *mw = &nt->mw[num_mw]; - struct pci_dev *pdev = ntb_query_pdev(nt->ndev); + struct ntb_transport_mw *mw = &nt->mw_vec[num_mw]; + struct pci_dev *pdev = nt->ndev->pdev; + unsigned int xlat_size, buff_size; + int rc; + + xlat_size = round_up(size, mw->xlat_align_size); + buff_size = round_up(size, mw->xlat_align); /* No need to re-setup */ - if (mw->size == ALIGN(size, 4096)) + if (mw->xlat_size == xlat_size) return 0; - if (mw->size != 0) + if (mw->buff_size) ntb_free_mw(nt, num_mw); - /* Alloc memory for receiving data. Must be 4k aligned */ - mw->size = ALIGN(size, 4096); + /* Alloc memory for receiving data. Must be aligned */ + mw->xlat_size = xlat_size; + mw->buff_size = buff_size; - mw->virt_addr = dma_alloc_coherent(&pdev->dev, mw->size, &mw->dma_addr, - GFP_KERNEL); + mw->virt_addr = dma_alloc_coherent(&pdev->dev, buff_size, + &mw->dma_addr, GFP_KERNEL); if (!mw->virt_addr) { - mw->size = 0; - dev_err(&pdev->dev, "Unable to allocate MW buffer of size %d\n", - (int) mw->size); + mw->xlat_size = 0; + mw->buff_size = 0; + dev_err(&pdev->dev, "Unable to alloc MW buff of size %d\n", + buff_size); return -ENOMEM; } @@ -582,34 +630,39 @@ static int ntb_set_mw(struct ntb_transport *nt, int num_mw, unsigned int size) * is a requirement of the hardware. It is recommended to setup CMA * for BAR sizes equal or greater than 4MB. */ - if (!IS_ALIGNED(mw->dma_addr, mw->size)) { - dev_err(&pdev->dev, "DMA memory %pad not aligned to BAR size\n", + if (!IS_ALIGNED(mw->dma_addr, mw->xlat_align)) { + dev_err(&pdev->dev, "DMA memory %pad is not aligned\n", &mw->dma_addr); ntb_free_mw(nt, num_mw); return -ENOMEM; } /* Notify HW the memory location of the receive buffer */ - ntb_set_mw_addr(nt->ndev, num_mw, mw->dma_addr); + rc = ntb_mw_set_trans(nt->ndev, num_mw, mw->dma_addr, mw->xlat_size); + if (rc) { + dev_err(&pdev->dev, "Unable to set mw%d translation", num_mw); + ntb_free_mw(nt, num_mw); + return -EIO; + } return 0; } static void ntb_qp_link_cleanup(struct ntb_transport_qp *qp) { - struct ntb_transport *nt = qp->transport; - struct pci_dev *pdev = ntb_query_pdev(nt->ndev); + struct ntb_transport_ctx *nt = qp->transport; + struct pci_dev *pdev = nt->ndev->pdev; - if (qp->qp_link == NTB_LINK_DOWN) { + if (qp->link_is_up) { cancel_delayed_work_sync(&qp->link_work); return; } - if (qp->event_handler) - qp->event_handler(qp->cb_data, NTB_LINK_DOWN); - dev_info(&pdev->dev, "qp %d: Link Down\n", qp->qp_num); - qp->qp_link = NTB_LINK_DOWN; + qp->link_is_up = false; + + if (qp->event_handler) + qp->event_handler(qp->cb_data, qp->link_is_up); } static void ntb_qp_link_cleanup_work(struct work_struct *work) @@ -617,11 +670,11 @@ static void ntb_qp_link_cleanup_work(struct work_struct *work) struct ntb_transport_qp *qp = container_of(work, struct ntb_transport_qp, link_cleanup); - struct ntb_transport *nt = qp->transport; + struct ntb_transport_ctx *nt = qp->transport; ntb_qp_link_cleanup(qp); - if (nt->transport_link == NTB_LINK_UP) + if (nt->link_is_up) schedule_delayed_work(&qp->link_work, msecs_to_jiffies(NTB_LINK_DOWN_TIMEOUT)); } @@ -631,180 +684,132 @@ static void ntb_qp_link_down(struct ntb_transport_qp *qp) schedule_work(&qp->link_cleanup); } -static void ntb_transport_link_cleanup(struct ntb_transport *nt) +static void ntb_transport_link_cleanup(struct ntb_transport_ctx *nt) { + struct ntb_transport_qp *qp; + u64 qp_bitmap_alloc; int i; + qp_bitmap_alloc = nt->qp_bitmap & ~nt->qp_bitmap_free; + /* Pass along the info to any clients */ - for (i = 0; i < nt->max_qps; i++) - if (!test_bit(i, &nt->qp_bitmap)) - ntb_qp_link_cleanup(&nt->qps[i]); + for (i = 0; i < nt->qp_count; i++) + if (qp_bitmap_alloc & BIT_ULL(i)) { + qp = &nt->qp_vec[i]; + ntb_qp_link_cleanup(qp); + cancel_work_sync(&qp->link_cleanup); + cancel_delayed_work_sync(&qp->link_work); + } - if (nt->transport_link == NTB_LINK_DOWN) + if (!nt->link_is_up) cancel_delayed_work_sync(&nt->link_work); - else - nt->transport_link = NTB_LINK_DOWN; /* The scratchpad registers keep the values if the remote side * goes down, blast them now to give them a sane value the next * time they are accessed */ for (i = 0; i < MAX_SPAD; i++) - ntb_write_local_spad(nt->ndev, i, 0); + ntb_spad_write(nt->ndev, i, 0); } static void ntb_transport_link_cleanup_work(struct work_struct *work) { - struct ntb_transport *nt = container_of(work, struct ntb_transport, - link_cleanup); + struct ntb_transport_ctx *nt = + container_of(work, struct ntb_transport_ctx, link_cleanup); ntb_transport_link_cleanup(nt); } -static void ntb_transport_event_callback(void *data, enum ntb_hw_event event) +static void ntb_transport_event_callback(void *data) { - struct ntb_transport *nt = data; + struct ntb_transport_ctx *nt = data; - switch (event) { - case NTB_EVENT_HW_LINK_UP: + if (ntb_link_is_up(nt->ndev, NULL, NULL) == 1) schedule_delayed_work(&nt->link_work, 0); - break; - case NTB_EVENT_HW_LINK_DOWN: + else schedule_work(&nt->link_cleanup); - break; - default: - BUG(); - } } static void ntb_transport_link_work(struct work_struct *work) { - struct ntb_transport *nt = container_of(work, struct ntb_transport, - link_work.work); - struct ntb_device *ndev = nt->ndev; - struct pci_dev *pdev = ntb_query_pdev(ndev); + struct ntb_transport_ctx *nt = + container_of(work, struct ntb_transport_ctx, link_work.work); + struct ntb_dev *ndev = nt->ndev; + struct pci_dev *pdev = ndev->pdev; + resource_size_t size; u32 val; - int rc, i; + int rc, i, spad; /* send the local info, in the opposite order of the way we read it */ - for (i = 0; i < ntb_max_mw(ndev); i++) { - rc = ntb_write_remote_spad(ndev, MW0_SZ_HIGH + (i * 2), - ntb_get_mw_size(ndev, i) >> 32); - if (rc) { - dev_err(&pdev->dev, "Error writing %u to remote spad %d\n", - (u32)(ntb_get_mw_size(ndev, i) >> 32), - MW0_SZ_HIGH + (i * 2)); - goto out; - } + for (i = 0; i < nt->mw_count; i++) { + size = nt->mw_vec[i].phys_size; - rc = ntb_write_remote_spad(ndev, MW0_SZ_LOW + (i * 2), - (u32) ntb_get_mw_size(ndev, i)); - if (rc) { - dev_err(&pdev->dev, "Error writing %u to remote spad %d\n", - (u32) ntb_get_mw_size(ndev, i), - MW0_SZ_LOW + (i * 2)); - goto out; - } - } + if (max_mw_size && size > max_mw_size) + size = max_mw_size; - rc = ntb_write_remote_spad(ndev, NUM_MWS, ntb_max_mw(ndev)); - if (rc) { - dev_err(&pdev->dev, "Error writing %x to remote spad %d\n", - ntb_max_mw(ndev), NUM_MWS); - goto out; - } + spad = MW0_SZ_HIGH + (i * 2); + ntb_peer_spad_write(ndev, spad, (u32)(size >> 32)); - rc = ntb_write_remote_spad(ndev, NUM_QPS, nt->max_qps); - if (rc) { - dev_err(&pdev->dev, "Error writing %x to remote spad %d\n", - nt->max_qps, NUM_QPS); - goto out; + spad = MW0_SZ_LOW + (i * 2); + ntb_peer_spad_write(ndev, spad, (u32)size); } - rc = ntb_write_remote_spad(ndev, VERSION, NTB_TRANSPORT_VERSION); - if (rc) { - dev_err(&pdev->dev, "Error writing %x to remote spad %d\n", - NTB_TRANSPORT_VERSION, VERSION); - goto out; - } + ntb_peer_spad_write(ndev, NUM_MWS, nt->mw_count); - /* Query the remote side for its info */ - rc = ntb_read_remote_spad(ndev, VERSION, &val); - if (rc) { - dev_err(&pdev->dev, "Error reading remote spad %d\n", VERSION); - goto out; - } + ntb_peer_spad_write(ndev, NUM_QPS, nt->qp_count); - if (val != NTB_TRANSPORT_VERSION) - goto out; - dev_dbg(&pdev->dev, "Remote version = %d\n", val); + ntb_peer_spad_write(ndev, VERSION, NTB_TRANSPORT_VERSION); - rc = ntb_read_remote_spad(ndev, NUM_QPS, &val); - if (rc) { - dev_err(&pdev->dev, "Error reading remote spad %d\n", NUM_QPS); + /* Query the remote side for its info */ + val = ntb_peer_spad_read(ndev, VERSION); + dev_dbg(&pdev->dev, "Remote version = %d\n", val); + if (val != NTB_TRANSPORT_VERSION) goto out; - } - if (val != nt->max_qps) - goto out; + val = ntb_peer_spad_read(ndev, NUM_QPS); dev_dbg(&pdev->dev, "Remote max number of qps = %d\n", val); - - rc = ntb_read_remote_spad(ndev, NUM_MWS, &val); - if (rc) { - dev_err(&pdev->dev, "Error reading remote spad %d\n", NUM_MWS); + if (val != nt->qp_count) goto out; - } - if (val != ntb_max_mw(ndev)) - goto out; + val = ntb_peer_spad_read(ndev, NUM_MWS); dev_dbg(&pdev->dev, "Remote number of mws = %d\n", val); + if (val != nt->mw_count) + goto out; - for (i = 0; i < ntb_max_mw(ndev); i++) { + for (i = 0; i < nt->mw_count; i++) { u64 val64; - rc = ntb_read_remote_spad(ndev, MW0_SZ_HIGH + (i * 2), &val); - if (rc) { - dev_err(&pdev->dev, "Error reading remote spad %d\n", - MW0_SZ_HIGH + (i * 2)); - goto out1; - } - - val64 = (u64) val << 32; - - rc = ntb_read_remote_spad(ndev, MW0_SZ_LOW + (i * 2), &val); - if (rc) { - dev_err(&pdev->dev, "Error reading remote spad %d\n", - MW0_SZ_LOW + (i * 2)); - goto out1; - } + val = ntb_peer_spad_read(ndev, MW0_SZ_HIGH + (i * 2)); + val64 = (u64)val << 32; + val = ntb_peer_spad_read(ndev, MW0_SZ_LOW + (i * 2)); val64 |= val; - dev_dbg(&pdev->dev, "Remote MW%d size = %llu\n", i, val64); + dev_dbg(&pdev->dev, "Remote MW%d size = %#llx\n", i, val64); rc = ntb_set_mw(nt, i, val64); if (rc) goto out1; } - nt->transport_link = NTB_LINK_UP; + nt->link_is_up = true; - for (i = 0; i < nt->max_qps; i++) { - struct ntb_transport_qp *qp = &nt->qps[i]; + for (i = 0; i < nt->qp_count; i++) { + struct ntb_transport_qp *qp = &nt->qp_vec[i]; ntb_transport_setup_qp_mw(nt, i); - if (qp->client_ready == NTB_LINK_UP) + if (qp->client_ready) schedule_delayed_work(&qp->link_work, 0); } return; out1: - for (i = 0; i < ntb_max_mw(ndev); i++) + for (i = 0; i < nt->mw_count; i++) ntb_free_mw(nt, i); out: - if (ntb_hw_link_status(ndev)) + if (ntb_link_is_up(ndev, NULL, NULL) == 1) schedule_delayed_work(&nt->link_work, msecs_to_jiffies(NTB_LINK_DOWN_TIMEOUT)); } @@ -814,73 +819,73 @@ static void ntb_qp_link_work(struct work_struct *work) struct ntb_transport_qp *qp = container_of(work, struct ntb_transport_qp, link_work.work); - struct pci_dev *pdev = ntb_query_pdev(qp->ndev); - struct ntb_transport *nt = qp->transport; - int rc, val; + struct pci_dev *pdev = qp->ndev->pdev; + struct ntb_transport_ctx *nt = qp->transport; + int val; - WARN_ON(nt->transport_link != NTB_LINK_UP); + WARN_ON(!nt->link_is_up); - rc = ntb_read_local_spad(nt->ndev, QP_LINKS, &val); - if (rc) { - dev_err(&pdev->dev, "Error reading spad %d\n", QP_LINKS); - return; - } + val = ntb_spad_read(nt->ndev, QP_LINKS); - rc = ntb_write_remote_spad(nt->ndev, QP_LINKS, val | 1 << qp->qp_num); - if (rc) - dev_err(&pdev->dev, "Error writing %x to remote spad %d\n", - val | 1 << qp->qp_num, QP_LINKS); + ntb_peer_spad_write(nt->ndev, QP_LINKS, val | BIT(qp->qp_num)); /* query remote spad for qp ready bits */ - rc = ntb_read_remote_spad(nt->ndev, QP_LINKS, &val); - if (rc) - dev_err(&pdev->dev, "Error reading remote spad %d\n", QP_LINKS); - + ntb_peer_spad_read(nt->ndev, QP_LINKS); dev_dbg(&pdev->dev, "Remote QP link status = %x\n", val); /* See if the remote side is up */ - if (1 << qp->qp_num & val) { - qp->qp_link = NTB_LINK_UP; - + if (val & BIT(qp->qp_num)) { dev_info(&pdev->dev, "qp %d: Link Up\n", qp->qp_num); + qp->link_is_up = true; + if (qp->event_handler) - qp->event_handler(qp->cb_data, NTB_LINK_UP); - } else if (nt->transport_link == NTB_LINK_UP) + qp->event_handler(qp->cb_data, qp->link_is_up); + } else if (nt->link_is_up) schedule_delayed_work(&qp->link_work, msecs_to_jiffies(NTB_LINK_DOWN_TIMEOUT)); } -static int ntb_transport_init_queue(struct ntb_transport *nt, +static int ntb_transport_init_queue(struct ntb_transport_ctx *nt, unsigned int qp_num) { struct ntb_transport_qp *qp; + struct ntb_transport_mw *mw; + phys_addr_t mw_base; + resource_size_t mw_size; unsigned int num_qps_mw, tx_size; - u8 mw_num, mw_max; + unsigned int mw_num, mw_count, qp_count; u64 qp_offset; - mw_max = ntb_max_mw(nt->ndev); - mw_num = QP_TO_MW(nt->ndev, qp_num); + mw_count = nt->mw_count; + qp_count = nt->qp_count; - qp = &nt->qps[qp_num]; + mw_num = QP_TO_MW(nt, qp_num); + mw = &nt->mw_vec[mw_num]; + + qp = &nt->qp_vec[qp_num]; qp->qp_num = qp_num; qp->transport = nt; qp->ndev = nt->ndev; - qp->qp_link = NTB_LINK_DOWN; - qp->client_ready = NTB_LINK_DOWN; + qp->link_is_up = false; + qp->client_ready = false; qp->event_handler = NULL; - if (nt->max_qps % mw_max && mw_num + 1 < nt->max_qps / mw_max) - num_qps_mw = nt->max_qps / mw_max + 1; + if (qp_count % mw_count && mw_num + 1 < qp_count / mw_count) + num_qps_mw = qp_count / mw_count + 1; else - num_qps_mw = nt->max_qps / mw_max; + num_qps_mw = qp_count / mw_count; + + mw_base = nt->mw_vec[mw_num].phys_addr; + mw_size = nt->mw_vec[mw_num].phys_size; - tx_size = (unsigned int) ntb_get_mw_size(qp->ndev, mw_num) / num_qps_mw; - qp_offset = qp_num / mw_max * tx_size; - qp->tx_mw = ntb_get_mw_vbase(nt->ndev, mw_num) + qp_offset; + tx_size = (unsigned int)mw_size / num_qps_mw; + qp_offset = tx_size * qp_num / mw_count; + + qp->tx_mw = nt->mw_vec[mw_num].vbase + qp_offset; if (!qp->tx_mw) return -EINVAL; - qp->tx_mw_phys = ntb_get_mw_base(qp->ndev, mw_num) + qp_offset; + qp->tx_mw_phys = mw_base + qp_offset; if (!qp->tx_mw_phys) return -EINVAL; @@ -891,16 +896,19 @@ static int ntb_transport_init_queue(struct ntb_transport *nt, qp->tx_max_frame = min(transport_mtu, tx_size / 2); qp->tx_max_entry = tx_size / qp->tx_max_frame; - if (ntb_query_debugfs(nt->ndev)) { + if (nt_debugfs_dir) { char debugfs_name[4]; snprintf(debugfs_name, 4, "qp%d", qp_num); qp->debugfs_dir = debugfs_create_dir(debugfs_name, - ntb_query_debugfs(nt->ndev)); + nt_debugfs_dir); qp->debugfs_stats = debugfs_create_file("stats", S_IRUSR, qp->debugfs_dir, qp, &ntb_qp_debugfs_stats); + } else { + qp->debugfs_dir = NULL; + qp->debugfs_stats = NULL; } INIT_DELAYED_WORK(&qp->link_work, ntb_qp_link_work); @@ -914,46 +922,84 @@ static int ntb_transport_init_queue(struct ntb_transport *nt, INIT_LIST_HEAD(&qp->rx_free_q); INIT_LIST_HEAD(&qp->tx_free_q); + tasklet_init(&qp->rxc_db_work, ntb_transport_rxc_db, + (unsigned long)qp); + return 0; } -int ntb_transport_init(struct pci_dev *pdev) +static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev) { - struct ntb_transport *nt; + struct ntb_transport_ctx *nt; + struct ntb_transport_mw *mw; + unsigned int mw_count, qp_count; + u64 qp_bitmap; int rc, i; - nt = kzalloc(sizeof(struct ntb_transport), GFP_KERNEL); + if (ntb_db_is_unsafe(ndev)) + dev_dbg(&ndev->dev, + "doorbell is unsafe, proceed anyway...\n"); + if (ntb_spad_is_unsafe(ndev)) + dev_dbg(&ndev->dev, + "scratchpad is unsafe, proceed anyway...\n"); + + nt = kzalloc(sizeof(*nt), GFP_KERNEL); if (!nt) return -ENOMEM; - nt->ndev = ntb_register_transport(pdev, nt); - if (!nt->ndev) { - rc = -EIO; + nt->ndev = ndev; + + mw_count = ntb_mw_count(ndev); + + nt->mw_count = mw_count; + + nt->mw_vec = kcalloc(mw_count, sizeof(*nt->mw_vec), GFP_KERNEL); + if (!nt->mw_vec) { + rc = -ENOMEM; goto err; } - nt->mw = kcalloc(ntb_max_mw(nt->ndev), sizeof(struct ntb_transport_mw), - GFP_KERNEL); - if (!nt->mw) { - rc = -ENOMEM; - goto err1; + for (i = 0; i < mw_count; i++) { + mw = &nt->mw_vec[i]; + + rc = ntb_mw_get_range(ndev, i, &mw->phys_addr, &mw->phys_size, + &mw->xlat_align, &mw->xlat_align_size); + if (rc) + goto err1; + + mw->vbase = ioremap(mw->phys_addr, mw->phys_size); + if (!mw->vbase) { + rc = -ENOMEM; + goto err1; + } + + mw->buff_size = 0; + mw->xlat_size = 0; + mw->virt_addr = NULL; + mw->dma_addr = 0; } - if (max_num_clients) - nt->max_qps = min(ntb_max_cbs(nt->ndev), max_num_clients); - else - nt->max_qps = min(ntb_max_cbs(nt->ndev), ntb_max_mw(nt->ndev)); + qp_bitmap = ntb_db_valid_mask(ndev); + + qp_count = ilog2(qp_bitmap); + if (max_num_clients && max_num_clients < qp_count) + qp_count = max_num_clients; + else if (mw_count < qp_count) + qp_count = mw_count; + + qp_bitmap &= BIT_ULL(qp_count) - 1; + + nt->qp_count = qp_count; + nt->qp_bitmap = qp_bitmap; + nt->qp_bitmap_free = qp_bitmap; - nt->qps = kcalloc(nt->max_qps, sizeof(struct ntb_transport_qp), - GFP_KERNEL); - if (!nt->qps) { + nt->qp_vec = kcalloc(qp_count, sizeof(*nt->qp_vec), GFP_KERNEL); + if (!nt->qp_vec) { rc = -ENOMEM; goto err2; } - nt->qp_bitmap = ((u64) 1 << nt->max_qps) - 1; - - for (i = 0; i < nt->max_qps; i++) { + for (i = 0; i < qp_count; i++) { rc = ntb_transport_init_queue(nt, i); if (rc) goto err3; @@ -962,8 +1008,7 @@ int ntb_transport_init(struct pci_dev *pdev) INIT_DELAYED_WORK(&nt->link_work, ntb_transport_link_work); INIT_WORK(&nt->link_cleanup, ntb_transport_link_cleanup_work); - rc = ntb_register_event_callback(nt->ndev, - ntb_transport_event_callback); + rc = ntb_set_ctx(ndev, nt, &ntb_transport_ops); if (rc) goto err3; @@ -972,51 +1017,61 @@ int ntb_transport_init(struct pci_dev *pdev) if (rc) goto err4; - if (ntb_hw_link_status(nt->ndev)) - schedule_delayed_work(&nt->link_work, 0); + nt->link_is_up = false; + ntb_link_enable(ndev, NTB_SPEED_AUTO, NTB_WIDTH_AUTO); + ntb_link_event(ndev); return 0; err4: - ntb_unregister_event_callback(nt->ndev); + ntb_clear_ctx(ndev); err3: - kfree(nt->qps); + kfree(nt->qp_vec); err2: - kfree(nt->mw); + kfree(nt->mw_vec); err1: - ntb_unregister_transport(nt->ndev); + while (i--) { + mw = &nt->mw_vec[i]; + iounmap(mw->vbase); + } err: kfree(nt); return rc; } -void ntb_transport_free(void *transport) +static void ntb_transport_free(struct ntb_client *self, struct ntb_dev *ndev) { - struct ntb_transport *nt = transport; - struct ntb_device *ndev = nt->ndev; + struct ntb_transport_ctx *nt = ndev->ctx; + struct ntb_transport_qp *qp; + u64 qp_bitmap_alloc; int i; ntb_transport_link_cleanup(nt); + cancel_work_sync(&nt->link_cleanup); + cancel_delayed_work_sync(&nt->link_work); + + qp_bitmap_alloc = nt->qp_bitmap & ~nt->qp_bitmap_free; /* verify that all the qp's are freed */ - for (i = 0; i < nt->max_qps; i++) { - if (!test_bit(i, &nt->qp_bitmap)) - ntb_transport_free_queue(&nt->qps[i]); - debugfs_remove_recursive(nt->qps[i].debugfs_dir); + for (i = 0; i < nt->qp_count; i++) { + qp = &nt->qp_vec[i]; + if (qp_bitmap_alloc & BIT_ULL(i)) + ntb_transport_free_queue(qp); + debugfs_remove_recursive(qp->debugfs_dir); } - ntb_bus_remove(nt); + ntb_link_disable(ndev); + ntb_clear_ctx(ndev); - cancel_delayed_work_sync(&nt->link_work); - - ntb_unregister_event_callback(ndev); + ntb_bus_remove(nt); - for (i = 0; i < ntb_max_mw(ndev); i++) + for (i = nt->mw_count; i--; ) { ntb_free_mw(nt, i); + iounmap(nt->mw_vec[i].vbase); + } - kfree(nt->qps); - kfree(nt->mw); - ntb_unregister_transport(ndev); + kfree(nt->qp_vec); + kfree(nt->mw_vec); kfree(nt); } @@ -1028,15 +1083,13 @@ static void ntb_rx_copy_callback(void *data) unsigned int len = entry->len; struct ntb_payload_header *hdr = entry->rx_hdr; - /* Ensure that the data is fully copied out before clearing the flag */ - wmb(); hdr->flags = 0; iowrite32(entry->index, &qp->rx_info->entry); ntb_list_add(&qp->ntb_rx_free_q_lock, &entry->entry, &qp->rx_free_q); - if (qp->rx_handler && qp->client_ready == NTB_LINK_UP) + if (qp->rx_handler && qp->client_ready) qp->rx_handler(qp, qp->cb_data, cb_data, len); } @@ -1047,6 +1100,9 @@ static void ntb_memcpy_rx(struct ntb_queue_entry *entry, void *offset) memcpy(buf, offset, len); + /* Ensure that the data is fully copied out before clearing the flag */ + wmb(); + ntb_rx_copy_callback(entry); } @@ -1071,8 +1127,8 @@ static void ntb_async_rx(struct ntb_queue_entry *entry, void *offset, goto err_wait; device = chan->device; - pay_off = (size_t) offset & ~PAGE_MASK; - buff_off = (size_t) buf & ~PAGE_MASK; + pay_off = (size_t)offset & ~PAGE_MASK; + buff_off = (size_t)buf & ~PAGE_MASK; if (!is_dma_copy_aligned(device, pay_off, buff_off, len)) goto err_wait; @@ -1138,86 +1194,104 @@ static int ntb_process_rxc(struct ntb_transport_qp *qp) struct ntb_payload_header *hdr; struct ntb_queue_entry *entry; void *offset; + int rc; offset = qp->rx_buff + qp->rx_max_frame * qp->rx_index; hdr = offset + qp->rx_max_frame - sizeof(struct ntb_payload_header); - entry = ntb_list_rm(&qp->ntb_rx_pend_q_lock, &qp->rx_pend_q); - if (!entry) { - dev_dbg(&ntb_query_pdev(qp->ndev)->dev, - "no buffer - HDR ver %u, len %d, flags %x\n", - hdr->ver, hdr->len, hdr->flags); - qp->rx_err_no_buf++; - return -ENOMEM; - } + dev_dbg(&qp->ndev->pdev->dev, "qp %d: RX ver %u len %d flags %x\n", + qp->qp_num, hdr->ver, hdr->len, hdr->flags); if (!(hdr->flags & DESC_DONE_FLAG)) { - ntb_list_add(&qp->ntb_rx_pend_q_lock, &entry->entry, - &qp->rx_pend_q); + dev_dbg(&qp->ndev->pdev->dev, "done flag not set\n"); qp->rx_ring_empty++; return -EAGAIN; } - if (hdr->ver != (u32) qp->rx_pkts) { - dev_dbg(&ntb_query_pdev(qp->ndev)->dev, - "qp %d: version mismatch, expected %llu - got %u\n", - qp->qp_num, qp->rx_pkts, hdr->ver); - ntb_list_add(&qp->ntb_rx_pend_q_lock, &entry->entry, - &qp->rx_pend_q); + if (hdr->flags & LINK_DOWN_FLAG) { + dev_dbg(&qp->ndev->pdev->dev, "link down flag set\n"); + ntb_qp_link_down(qp); + hdr->flags = 0; + iowrite32(qp->rx_index, &qp->rx_info->entry); + return 0; + } + + if (hdr->ver != (u32)qp->rx_pkts) { + dev_dbg(&qp->ndev->pdev->dev, + "version mismatch, expected %llu - got %u\n", + qp->rx_pkts, hdr->ver); qp->rx_err_ver++; return -EIO; } - if (hdr->flags & LINK_DOWN_FLAG) { - ntb_qp_link_down(qp); + entry = ntb_list_rm(&qp->ntb_rx_pend_q_lock, &qp->rx_pend_q); + if (!entry) { + dev_dbg(&qp->ndev->pdev->dev, "no receive buffer\n"); + qp->rx_err_no_buf++; + rc = -ENOMEM; goto err; } - dev_dbg(&ntb_query_pdev(qp->ndev)->dev, - "rx offset %u, ver %u - %d payload received, buf size %d\n", - qp->rx_index, hdr->ver, hdr->len, entry->len); - - qp->rx_bytes += hdr->len; - qp->rx_pkts++; - if (hdr->len > entry->len) { - qp->rx_err_oflow++; - dev_dbg(&ntb_query_pdev(qp->ndev)->dev, - "RX overflow! Wanted %d got %d\n", + dev_dbg(&qp->ndev->pdev->dev, + "receive buffer overflow! Wanted %d got %d\n", hdr->len, entry->len); + qp->rx_err_oflow++; + rc = -EIO; goto err; } + dev_dbg(&qp->ndev->pdev->dev, + "RX OK index %u ver %u size %d into buf size %d\n", + qp->rx_index, hdr->ver, hdr->len, entry->len); + + qp->rx_bytes += hdr->len; + qp->rx_pkts++; + entry->index = qp->rx_index; entry->rx_hdr = hdr; ntb_async_rx(entry, offset, hdr->len); -out: qp->rx_index++; qp->rx_index %= qp->rx_max_entry; return 0; err: - ntb_list_add(&qp->ntb_rx_pend_q_lock, &entry->entry, &qp->rx_pend_q); - /* Ensure that the data is fully copied out before clearing the flag */ - wmb(); + /* FIXME: if this syncrhonous update of the rx_index gets ahead of + * asyncrhonous ntb_rx_copy_callback of previous entry, there are three + * scenarios: + * + * 1) The peer might miss this update, but observe the update + * from the memcpy completion callback. In this case, the buffer will + * not be freed on the peer to be reused for a different packet. The + * successful rx of a later packet would clear the condition, but the + * condition could persist if several rx fail in a row. + * + * 2) The peer may observe this update before the asyncrhonous copy of + * prior packets is completed. The peer may overwrite the buffers of + * the prior packets before they are copied. + * + * 3) Both: the peer may observe the update, and then observe the index + * decrement by the asynchronous completion callback. Who knows what + * badness that will cause. + */ hdr->flags = 0; iowrite32(qp->rx_index, &qp->rx_info->entry); - goto out; + return rc; } -static int ntb_transport_rxc_db(void *data, int db_num) +static void ntb_transport_rxc_db(unsigned long data) { - struct ntb_transport_qp *qp = data; + struct ntb_transport_qp *qp = (void *)data; int rc, i; - dev_dbg(&ntb_query_pdev(qp->ndev)->dev, "%s: doorbell %d received\n", - __func__, db_num); + dev_dbg(&qp->ndev->pdev->dev, "%s: doorbell %d received\n", + __func__, qp->qp_num); /* Limit the number of packets processed in a single interrupt to * provide fairness to others @@ -1231,7 +1305,21 @@ static int ntb_transport_rxc_db(void *data, int db_num) if (qp->dma_chan) dma_async_issue_pending(qp->dma_chan); - return i; + if (i == qp->rx_max_entry) { + /* there is more work to do */ + tasklet_schedule(&qp->rxc_db_work); + } else if (ntb_db_read(qp->ndev) & BIT_ULL(qp->qp_num)) { + /* the doorbell bit is set: clear it */ + ntb_db_clear(qp->ndev, BIT_ULL(qp->qp_num)); + /* ntb_db_read ensures ntb_db_clear write is committed */ + ntb_db_read(qp->ndev); + + /* an interrupt may have arrived between finishing + * ntb_process_rxc and clearing the doorbell bit: + * there might be some more work to do. + */ + tasklet_schedule(&qp->rxc_db_work); + } } static void ntb_tx_copy_callback(void *data) @@ -1240,11 +1328,9 @@ static void ntb_tx_copy_callback(void *data) struct ntb_transport_qp *qp = entry->qp; struct ntb_payload_header __iomem *hdr = entry->tx_hdr; - /* Ensure that the data is fully copied out before setting the flags */ - wmb(); iowrite32(entry->flags | DESC_DONE_FLAG, &hdr->flags); - ntb_ring_doorbell(qp->ndev, qp->qp_num); + ntb_peer_db_set(qp->ndev, BIT_ULL(qp->qp_num)); /* The entry length can only be zero if the packet is intended to be a * "link down" or similar. Since no payload is being sent in these @@ -1265,6 +1351,9 @@ static void ntb_memcpy_tx(struct ntb_queue_entry *entry, void __iomem *offset) { memcpy_toio(offset, entry->buf, entry->len); + /* Ensure that the data is fully copied out before setting the flags */ + wmb(); + ntb_tx_copy_callback(entry); } @@ -1288,7 +1377,7 @@ static void ntb_async_tx(struct ntb_transport_qp *qp, entry->tx_hdr = hdr; iowrite32(entry->len, &hdr->len); - iowrite32((u32) qp->tx_pkts, &hdr->ver); + iowrite32((u32)qp->tx_pkts, &hdr->ver); if (!chan) goto err; @@ -1298,8 +1387,8 @@ static void ntb_async_tx(struct ntb_transport_qp *qp, device = chan->device; dest = qp->tx_mw_phys + qp->tx_max_frame * qp->tx_index; - buff_off = (size_t) buf & ~PAGE_MASK; - dest_off = (size_t) dest & ~PAGE_MASK; + buff_off = (size_t)buf & ~PAGE_MASK; + dest_off = (size_t)dest & ~PAGE_MASK; if (!is_dma_copy_aligned(device, buff_off, dest_off, len)) goto err; @@ -1347,9 +1436,6 @@ err: static int ntb_process_tx(struct ntb_transport_qp *qp, struct ntb_queue_entry *entry) { - dev_dbg(&ntb_query_pdev(qp->ndev)->dev, "%lld - tx %u, entry len %d flags %x buff %p\n", - qp->tx_pkts, qp->tx_index, entry->len, entry->flags, - entry->buf); if (qp->tx_index == qp->remote_rx_info->entry) { qp->tx_ring_full++; return -EAGAIN; @@ -1376,14 +1462,14 @@ static int ntb_process_tx(struct ntb_transport_qp *qp, static void ntb_send_link_down(struct ntb_transport_qp *qp) { - struct pci_dev *pdev = ntb_query_pdev(qp->ndev); + struct pci_dev *pdev = qp->ndev->pdev; struct ntb_queue_entry *entry; int i, rc; - if (qp->qp_link == NTB_LINK_DOWN) + if (!qp->link_is_up) return; - qp->qp_link = NTB_LINK_DOWN; + qp->link_is_up = false; dev_info(&pdev->dev, "qp %d: Link Down\n", qp->qp_num); for (i = 0; i < NTB_LINK_DOWN_TIMEOUT; i++) { @@ -1422,18 +1508,21 @@ static void ntb_send_link_down(struct ntb_transport_qp *qp) * RETURNS: pointer to newly created ntb_queue, NULL on error. */ struct ntb_transport_qp * -ntb_transport_create_queue(void *data, struct pci_dev *pdev, +ntb_transport_create_queue(void *data, struct device *client_dev, const struct ntb_queue_handlers *handlers) { + struct ntb_dev *ndev; + struct pci_dev *pdev; + struct ntb_transport_ctx *nt; struct ntb_queue_entry *entry; struct ntb_transport_qp *qp; - struct ntb_transport *nt; + u64 qp_bit; unsigned int free_queue; - int rc, i; + int i; - nt = ntb_find_transport(pdev); - if (!nt) - goto err; + ndev = dev_ntb(client_dev->parent); + pdev = ndev->pdev; + nt = ndev->ctx; free_queue = ffs(nt->qp_bitmap); if (!free_queue) @@ -1442,9 +1531,11 @@ ntb_transport_create_queue(void *data, struct pci_dev *pdev, /* decrement free_queue to make it zero based */ free_queue--; - clear_bit(free_queue, &nt->qp_bitmap); + qp = &nt->qp_vec[free_queue]; + qp_bit = BIT_ULL(qp->qp_num); + + nt->qp_bitmap_free &= ~qp_bit; - qp = &nt->qps[free_queue]; qp->cb_data = data; qp->rx_handler = handlers->rx_handler; qp->tx_handler = handlers->tx_handler; @@ -1458,7 +1549,7 @@ ntb_transport_create_queue(void *data, struct pci_dev *pdev, } for (i = 0; i < NTB_QP_DEF_NUM_ENTRIES; i++) { - entry = kzalloc(sizeof(struct ntb_queue_entry), GFP_ATOMIC); + entry = kzalloc(sizeof(*entry), GFP_ATOMIC); if (!entry) goto err1; @@ -1468,7 +1559,7 @@ ntb_transport_create_queue(void *data, struct pci_dev *pdev, } for (i = 0; i < NTB_QP_DEF_NUM_ENTRIES; i++) { - entry = kzalloc(sizeof(struct ntb_queue_entry), GFP_ATOMIC); + entry = kzalloc(sizeof(*entry), GFP_ATOMIC); if (!entry) goto err2; @@ -1477,10 +1568,8 @@ ntb_transport_create_queue(void *data, struct pci_dev *pdev, &qp->tx_free_q); } - rc = ntb_register_db_callback(qp->ndev, free_queue, qp, - ntb_transport_rxc_db); - if (rc) - goto err2; + ntb_db_clear(qp->ndev, qp_bit); + ntb_db_clear_mask(qp->ndev, qp_bit); dev_info(&pdev->dev, "NTB Transport QP %d created\n", qp->qp_num); @@ -1494,7 +1583,7 @@ err1: kfree(entry); if (qp->dma_chan) dmaengine_put(); - set_bit(free_queue, &nt->qp_bitmap); + nt->qp_bitmap_free |= qp_bit; err: return NULL; } @@ -1508,13 +1597,15 @@ EXPORT_SYMBOL_GPL(ntb_transport_create_queue); */ void ntb_transport_free_queue(struct ntb_transport_qp *qp) { + struct ntb_transport_ctx *nt = qp->transport; struct pci_dev *pdev; struct ntb_queue_entry *entry; + u64 qp_bit; if (!qp) return; - pdev = ntb_query_pdev(qp->ndev); + pdev = qp->ndev->pdev; if (qp->dma_chan) { struct dma_chan *chan = qp->dma_chan; @@ -1531,10 +1622,18 @@ void ntb_transport_free_queue(struct ntb_transport_qp *qp) dmaengine_put(); } - ntb_unregister_db_callback(qp->ndev, qp->qp_num); + qp_bit = BIT_ULL(qp->qp_num); + + ntb_db_set_mask(qp->ndev, qp_bit); + tasklet_disable(&qp->rxc_db_work); cancel_delayed_work_sync(&qp->link_work); + qp->cb_data = NULL; + qp->rx_handler = NULL; + qp->tx_handler = NULL; + qp->event_handler = NULL; + while ((entry = ntb_list_rm(&qp->ntb_rx_free_q_lock, &qp->rx_free_q))) kfree(entry); @@ -1546,7 +1645,7 @@ void ntb_transport_free_queue(struct ntb_transport_qp *qp) while ((entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q))) kfree(entry); - set_bit(qp->qp_num, &qp->transport->qp_bitmap); + nt->qp_bitmap_free |= qp_bit; dev_info(&pdev->dev, "NTB Transport QP %d freed\n", qp->qp_num); } @@ -1567,7 +1666,7 @@ void *ntb_transport_rx_remove(struct ntb_transport_qp *qp, unsigned int *len) struct ntb_queue_entry *entry; void *buf; - if (!qp || qp->client_ready == NTB_LINK_UP) + if (!qp || qp->client_ready) return NULL; entry = ntb_list_rm(&qp->ntb_rx_pend_q_lock, &qp->rx_pend_q); @@ -1636,7 +1735,7 @@ int ntb_transport_tx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data, struct ntb_queue_entry *entry; int rc; - if (!qp || qp->qp_link != NTB_LINK_UP || !len) + if (!qp || !qp->link_is_up || !len) return -EINVAL; entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q); @@ -1670,9 +1769,9 @@ void ntb_transport_link_up(struct ntb_transport_qp *qp) if (!qp) return; - qp->client_ready = NTB_LINK_UP; + qp->client_ready = true; - if (qp->transport->transport_link == NTB_LINK_UP) + if (qp->transport->link_is_up) schedule_delayed_work(&qp->link_work, 0); } EXPORT_SYMBOL_GPL(ntb_transport_link_up); @@ -1688,27 +1787,20 @@ EXPORT_SYMBOL_GPL(ntb_transport_link_up); void ntb_transport_link_down(struct ntb_transport_qp *qp) { struct pci_dev *pdev; - int rc, val; + int val; if (!qp) return; - pdev = ntb_query_pdev(qp->ndev); - qp->client_ready = NTB_LINK_DOWN; + pdev = qp->ndev->pdev; + qp->client_ready = false; - rc = ntb_read_local_spad(qp->ndev, QP_LINKS, &val); - if (rc) { - dev_err(&pdev->dev, "Error reading spad %d\n", QP_LINKS); - return; - } + val = ntb_spad_read(qp->ndev, QP_LINKS); - rc = ntb_write_remote_spad(qp->ndev, QP_LINKS, - val & ~(1 << qp->qp_num)); - if (rc) - dev_err(&pdev->dev, "Error writing %x to remote spad %d\n", - val & ~(1 << qp->qp_num), QP_LINKS); + ntb_peer_spad_write(qp->ndev, QP_LINKS, + val & ~BIT(qp->qp_num)); - if (qp->qp_link == NTB_LINK_UP) + if (qp->link_is_up) ntb_send_link_down(qp); else cancel_delayed_work_sync(&qp->link_work); @@ -1728,7 +1820,7 @@ bool ntb_transport_link_query(struct ntb_transport_qp *qp) if (!qp) return false; - return qp->qp_link == NTB_LINK_UP; + return qp->link_is_up; } EXPORT_SYMBOL_GPL(ntb_transport_link_query); @@ -1774,3 +1866,69 @@ unsigned int ntb_transport_max_size(struct ntb_transport_qp *qp) return max; } EXPORT_SYMBOL_GPL(ntb_transport_max_size); + +static void ntb_transport_doorbell_callback(void *data, int vector) +{ + struct ntb_transport_ctx *nt = data; + struct ntb_transport_qp *qp; + u64 db_bits; + unsigned int qp_num; + + db_bits = (nt->qp_bitmap & ~nt->qp_bitmap_free & + ntb_db_vector_mask(nt->ndev, vector)); + + while (db_bits) { + qp_num = __ffs(db_bits); + qp = &nt->qp_vec[qp_num]; + + tasklet_schedule(&qp->rxc_db_work); + + db_bits &= ~BIT_ULL(qp_num); + } +} + +static const struct ntb_ctx_ops ntb_transport_ops = { + .link_event = ntb_transport_event_callback, + .db_event = ntb_transport_doorbell_callback, +}; + +static struct ntb_client ntb_transport_client = { + .ops = { + .probe = ntb_transport_probe, + .remove = ntb_transport_free, + }, +}; + +static int __init ntb_transport_init(void) +{ + int rc; + + if (debugfs_initialized()) + nt_debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL); + + rc = bus_register(&ntb_transport_bus); + if (rc) + goto err_bus; + + rc = ntb_register_client(&ntb_transport_client); + if (rc) + goto err_client; + + return 0; + +err_client: + bus_unregister(&ntb_transport_bus); +err_bus: + debugfs_remove_recursive(nt_debugfs_dir); + return rc; +} +module_init(ntb_transport_init); + +static void __exit ntb_transport_exit(void) +{ + debugfs_remove_recursive(nt_debugfs_dir); + + ntb_unregister_client(&ntb_transport_client); + bus_unregister(&ntb_transport_bus); +} +module_exit(ntb_transport_exit); diff --git a/include/linux/ntb_transport.h b/include/linux/ntb_transport.h index f78b64cc09d5..2862861366a5 100644 --- a/include/linux/ntb_transport.h +++ b/include/linux/ntb_transport.h @@ -5,6 +5,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 Intel Corporation. All rights reserved. + * Copyright (C) 2015 EMC Corporation. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -13,6 +14,7 @@ * BSD LICENSE * * Copyright(c) 2012 Intel Corporation. All rights reserved. + * Copyright (C) 2015 EMC Corporation. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -40,7 +42,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Intel PCIe NTB Linux driver + * PCIe NTB Transport Linux driver * * Contact Information: * Jon Mason @@ -48,21 +50,16 @@ struct ntb_transport_qp; -struct ntb_client { +struct ntb_transport_client { struct device_driver driver; - int (*probe)(struct pci_dev *pdev); - void (*remove)(struct pci_dev *pdev); + int (*probe)(struct device *client_dev); + void (*remove)(struct device *client_dev); }; -enum { - NTB_LINK_DOWN = 0, - NTB_LINK_UP, -}; - -int ntb_transport_register_client(struct ntb_client *drvr); -void ntb_transport_unregister_client(struct ntb_client *drvr); -int ntb_register_client_dev(char *device_name); -void ntb_unregister_client_dev(char *device_name); +int ntb_transport_register_client(struct ntb_transport_client *drvr); +void ntb_transport_unregister_client(struct ntb_transport_client *drvr); +int ntb_transport_register_client_dev(char *device_name); +void ntb_transport_unregister_client_dev(char *device_name); struct ntb_queue_handlers { void (*rx_handler)(struct ntb_transport_qp *qp, void *qp_data, @@ -75,7 +72,7 @@ struct ntb_queue_handlers { unsigned char ntb_transport_qp_num(struct ntb_transport_qp *qp); unsigned int ntb_transport_max_size(struct ntb_transport_qp *qp); struct ntb_transport_qp * -ntb_transport_create_queue(void *data, struct pci_dev *pdev, +ntb_transport_create_queue(void *data, struct device *client_dev, const struct ntb_queue_handlers *handlers); void ntb_transport_free_queue(struct ntb_transport_qp *qp); int ntb_transport_rx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data, -- cgit v1.2.3-70-g09d2 From 0f69a7dff94d3e82ee51685f6a8fea7860b023b8 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Tue, 2 Jun 2015 03:45:07 -0400 Subject: NTB: Read peer info from local SPAD in transport The transport was writing and then reading the peer scratch pad, essentially reading what it just wrote instead of exchanging any information with the peer. The transport expects the peer values to be the same as the local values, so this issue was not obvious. Signed-off-by: Dave Jiang Signed-off-by: Jon Mason --- drivers/ntb/ntb_transport.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index 9faf1c6029af..d9538e911df6 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c @@ -761,17 +761,17 @@ static void ntb_transport_link_work(struct work_struct *work) ntb_peer_spad_write(ndev, VERSION, NTB_TRANSPORT_VERSION); /* Query the remote side for its info */ - val = ntb_peer_spad_read(ndev, VERSION); + val = ntb_spad_read(ndev, VERSION); dev_dbg(&pdev->dev, "Remote version = %d\n", val); if (val != NTB_TRANSPORT_VERSION) goto out; - val = ntb_peer_spad_read(ndev, NUM_QPS); + val = ntb_spad_read(ndev, NUM_QPS); dev_dbg(&pdev->dev, "Remote max number of qps = %d\n", val); if (val != nt->qp_count) goto out; - val = ntb_peer_spad_read(ndev, NUM_MWS); + val = ntb_spad_read(ndev, NUM_MWS); dev_dbg(&pdev->dev, "Remote number of mws = %d\n", val); if (val != nt->mw_count) goto out; @@ -779,10 +779,10 @@ static void ntb_transport_link_work(struct work_struct *work) for (i = 0; i < nt->mw_count; i++) { u64 val64; - val = ntb_peer_spad_read(ndev, MW0_SZ_HIGH + (i * 2)); + val = ntb_spad_read(ndev, MW0_SZ_HIGH + (i * 2)); val64 = (u64)val << 32; - val = ntb_peer_spad_read(ndev, MW0_SZ_LOW + (i * 2)); + val = ntb_spad_read(ndev, MW0_SZ_LOW + (i * 2)); val64 |= val; dev_dbg(&pdev->dev, "Remote MW%d size = %#llx\n", i, val64); -- cgit v1.2.3-70-g09d2 From 5ae0beb6bcb781ba0439618a4883fdb243916f46 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Tue, 19 May 2015 16:59:34 -0400 Subject: NTB: Enable link for Intel root port mode in probe Link training should be enabled in the driver probe for root port mode. We should not have to wait for transport to be loaded for this to happen. Otherwise the ntb device will not show up on the transparent bridge side of the link. Signed-off-by: Dave Jiang Signed-off-by: Jon Mason --- drivers/ntb/hw/intel/ntb_hw_intel.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c index 686091756ba4..3810ad11cfdf 100644 --- a/drivers/ntb/hw/intel/ntb_hw_intel.c +++ b/drivers/ntb/hw/intel/ntb_hw_intel.c @@ -1317,6 +1317,9 @@ static int snb_poll_link(struct intel_ntb_dev *ndev) static int snb_link_is_up(struct intel_ntb_dev *ndev) { + if (ndev->ntb.topo == NTB_TOPO_SEC) + return 1; + return NTB_LNK_STA_ACTIVE(ndev->lnk_sta); } @@ -1613,6 +1616,7 @@ static int snb_setup_b2b_mw(struct intel_ntb_dev *ndev, static int snb_init_ntb(struct intel_ntb_dev *ndev) { int rc; + u32 ntb_ctl; if (ndev->bar4_split) ndev->mw_count = HSX_SPLIT_BAR_MW_COUNT; @@ -1629,6 +1633,12 @@ static int snb_init_ntb(struct intel_ntb_dev *ndev) dev_err(ndev_dev(ndev), "NTB Primary config disabled\n"); return -EINVAL; } + + /* enable link to allow secondary side device to appear */ + ntb_ctl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl); + ntb_ctl &= ~NTB_CTL_DISABLE; + iowrite32(ntb_ctl, ndev->self_mmio + ndev->reg->ntb_ctl); + /* use half the spads for the peer */ ndev->spad_count >>= 1; ndev->self_reg = &snb_pri_reg; -- cgit v1.2.3-70-g09d2 From dd5d4d8edb6b40f75e5c8f0db65a4562bffc2e00 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Fri, 8 May 2015 12:24:40 -0400 Subject: NTB: Check the device ID to set errata flags Set errata flags for the specific device IDs to which they apply, instead of the whole Xeon hardware class. Signed-off-by: Dave Jiang Signed-off-by: Jon Mason --- drivers/ntb/hw/intel/ntb_hw_intel.c | 49 +++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c index 3810ad11cfdf..499222285439 100644 --- a/drivers/ntb/hw/intel/ntb_hw_intel.c +++ b/drivers/ntb/hw/intel/ntb_hw_intel.c @@ -1718,29 +1718,68 @@ static int snb_init_dev(struct intel_ntb_dev *ndev) u8 ppd; int rc, mem; + pdev = ndev_pdev(ndev); + + switch (pdev->device) { /* There is a Xeon hardware errata related to writes to SDOORBELL or * B2BDOORBELL in conjunction with inbound access to NTB MMIO Space, * which may hang the system. To workaround this use the second memory * window to access the interrupt and scratch pad registers on the * remote system. */ - ndev->hwerr_flags |= NTB_HWERR_SDOORBELL_LOCKUP; + case PCI_DEVICE_ID_INTEL_NTB_SS_JSF: + case PCI_DEVICE_ID_INTEL_NTB_PS_JSF: + case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF: + case PCI_DEVICE_ID_INTEL_NTB_SS_SNB: + case PCI_DEVICE_ID_INTEL_NTB_PS_SNB: + case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB: + case PCI_DEVICE_ID_INTEL_NTB_SS_IVT: + case PCI_DEVICE_ID_INTEL_NTB_PS_IVT: + case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT: + case PCI_DEVICE_ID_INTEL_NTB_SS_HSX: + case PCI_DEVICE_ID_INTEL_NTB_PS_HSX: + case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX: + ndev->hwerr_flags |= NTB_HWERR_SDOORBELL_LOCKUP; + break; + } + switch (pdev->device) { /* There is a hardware errata related to accessing any register in * SB01BASE in the presence of bidirectional traffic crossing the NTB. */ - ndev->hwerr_flags |= NTB_HWERR_SB01BASE_LOCKUP; + case PCI_DEVICE_ID_INTEL_NTB_SS_IVT: + case PCI_DEVICE_ID_INTEL_NTB_PS_IVT: + case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT: + case PCI_DEVICE_ID_INTEL_NTB_SS_HSX: + case PCI_DEVICE_ID_INTEL_NTB_PS_HSX: + case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX: + ndev->hwerr_flags |= NTB_HWERR_SB01BASE_LOCKUP; + break; + } + switch (pdev->device) { /* HW Errata on bit 14 of b2bdoorbell register. Writes will not be * mirrored to the remote system. Shrink the number of bits by one, * since bit 14 is the last bit. */ - ndev->hwerr_flags |= NTB_HWERR_B2BDOORBELL_BIT14; + case PCI_DEVICE_ID_INTEL_NTB_SS_JSF: + case PCI_DEVICE_ID_INTEL_NTB_PS_JSF: + case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF: + case PCI_DEVICE_ID_INTEL_NTB_SS_SNB: + case PCI_DEVICE_ID_INTEL_NTB_PS_SNB: + case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB: + case PCI_DEVICE_ID_INTEL_NTB_SS_IVT: + case PCI_DEVICE_ID_INTEL_NTB_PS_IVT: + case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT: + case PCI_DEVICE_ID_INTEL_NTB_SS_HSX: + case PCI_DEVICE_ID_INTEL_NTB_PS_HSX: + case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX: + ndev->hwerr_flags |= NTB_HWERR_B2BDOORBELL_BIT14; + break; + } ndev->reg = &snb_reg; - pdev = ndev_pdev(ndev); - rc = pci_read_config_byte(pdev, SNB_PPD_OFFSET, &ppd); if (rc) return -EIO; -- cgit v1.2.3-70-g09d2 From e22e0b9dcf78ee7a72561a6770c9ea554eb65096 Mon Sep 17 00:00:00 2001 From: Allen Hubbe Date: Tue, 12 May 2015 06:55:44 -0400 Subject: NTB: Differentiate transport link down messages The same message "qp %d: Link Down\n" was printed at two locations in ntb_transport. Change the messages so they are distinct. Signed-off-by: Allen Hubbe Signed-off-by: Jon Mason --- drivers/ntb/ntb_transport.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index d9538e911df6..8d9b59f7fa07 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c @@ -658,7 +658,7 @@ static void ntb_qp_link_cleanup(struct ntb_transport_qp *qp) return; } - dev_info(&pdev->dev, "qp %d: Link Down\n", qp->qp_num); + dev_info(&pdev->dev, "qp %d: Link Cleanup\n", qp->qp_num); qp->link_is_up = false; if (qp->event_handler) @@ -1470,7 +1470,7 @@ static void ntb_send_link_down(struct ntb_transport_qp *qp) return; qp->link_is_up = false; - dev_info(&pdev->dev, "qp %d: Link Down\n", qp->qp_num); + dev_info(&pdev->dev, "qp %d: Send Link Down\n", qp->qp_num); for (i = 0; i < NTB_LINK_DOWN_TIMEOUT; i++) { entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q); -- cgit v1.2.3-70-g09d2 From c0900b33d1c8c24246eaedb9553f078024c332fc Mon Sep 17 00:00:00 2001 From: Allen Hubbe Date: Tue, 12 May 2015 06:24:27 -0400 Subject: NTB: Do not advance transport RX on link down On link down, don't advance RX index to the next entry. The next entry should never be valid after receiving the link down flag. Signed-off-by: Allen Hubbe Signed-off-by: Jon Mason --- drivers/ntb/ntb_transport.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index 8d9b59f7fa07..0f86b60a0c0e 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c @@ -1212,8 +1212,7 @@ static int ntb_process_rxc(struct ntb_transport_qp *qp) dev_dbg(&qp->ndev->pdev->dev, "link down flag set\n"); ntb_qp_link_down(qp); hdr->flags = 0; - iowrite32(qp->rx_index, &qp->rx_info->entry); - return 0; + return -EAGAIN; } if (hdr->ver != (u32)qp->rx_pkts) { -- cgit v1.2.3-70-g09d2 From 2849b5d70641db76f9b674d00c6d204892c51515 Mon Sep 17 00:00:00 2001 From: Allen Hubbe Date: Tue, 12 May 2015 08:09:15 -0400 Subject: NTB: Reset transport QP link stats on down Reset the link stats when the link goes down. In particular, the TX and RX index and count must be reset, or else the TX side will be sending packets to the RX side where the RX side is not expecting them. Reset all the stats, to be consistent. Signed-off-by: Allen Hubbe Signed-off-by: Jon Mason --- drivers/ntb/ntb_transport.c | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index 0f86b60a0c0e..2efd1eae9a7c 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c @@ -648,18 +648,37 @@ static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw, return 0; } +static void ntb_qp_link_down_reset(struct ntb_transport_qp *qp) +{ + qp->link_is_up = false; + + qp->tx_index = 0; + qp->rx_index = 0; + qp->rx_bytes = 0; + qp->rx_pkts = 0; + qp->rx_ring_empty = 0; + qp->rx_err_no_buf = 0; + qp->rx_err_oflow = 0; + qp->rx_err_ver = 0; + qp->rx_memcpy = 0; + qp->rx_async = 0; + qp->tx_bytes = 0; + qp->tx_pkts = 0; + qp->tx_ring_full = 0; + qp->tx_err_no_buf = 0; + qp->tx_memcpy = 0; + qp->tx_async = 0; +} + static void ntb_qp_link_cleanup(struct ntb_transport_qp *qp) { struct ntb_transport_ctx *nt = qp->transport; struct pci_dev *pdev = nt->ndev->pdev; - if (qp->link_is_up) { - cancel_delayed_work_sync(&qp->link_work); - return; - } - dev_info(&pdev->dev, "qp %d: Link Cleanup\n", qp->qp_num); - qp->link_is_up = false; + + cancel_delayed_work_sync(&qp->link_work); + ntb_qp_link_down_reset(qp); if (qp->event_handler) qp->event_handler(qp->cb_data, qp->link_is_up); @@ -866,9 +885,9 @@ static int ntb_transport_init_queue(struct ntb_transport_ctx *nt, qp->qp_num = qp_num; qp->transport = nt; qp->ndev = nt->ndev; - qp->link_is_up = false; qp->client_ready = false; qp->event_handler = NULL; + ntb_qp_link_down_reset(qp); if (qp_count % mw_count && mw_num + 1 < qp_count / mw_count) num_qps_mw = qp_count / mw_count + 1; @@ -1468,7 +1487,6 @@ static void ntb_send_link_down(struct ntb_transport_qp *qp) if (!qp->link_is_up) return; - qp->link_is_up = false; dev_info(&pdev->dev, "qp %d: Send Link Down\n", qp->qp_num); for (i = 0; i < NTB_LINK_DOWN_TIMEOUT; i++) { @@ -1490,6 +1508,8 @@ static void ntb_send_link_down(struct ntb_transport_qp *qp) if (rc) dev_err(&pdev->dev, "ntb: QP%d unable to send linkdown msg\n", qp->qp_num); + + ntb_qp_link_down_reset(qp); } /** -- cgit v1.2.3-70-g09d2 From 42fefc86a680f975e2816cd86c4ba50069766ef6 Mon Sep 17 00:00:00 2001 From: Allen Hubbe Date: Mon, 11 May 2015 05:45:30 -0400 Subject: NTB: Add parameters for Intel SNB B2B addresses Add module parameters for the addresses to be used in B2B topology. Signed-off-by: Allen Hubbe Signed-off-by: Jon Mason --- Documentation/ntb.txt | 10 +++++ drivers/ntb/hw/intel/ntb_hw_intel.c | 77 ++++++++++++++++++++++++++++--------- 2 files changed, 68 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/Documentation/ntb.txt b/Documentation/ntb.txt index 725ba1e6c127..00a3f92832a5 100644 --- a/Documentation/ntb.txt +++ b/Documentation/ntb.txt @@ -56,3 +56,13 @@ Module Parameters: * b2b\_mw\_share - If the peer ntb is to be accessed via a memory window, and if the memory window is large enough, still allow the client to use the second half of the memory window for address translation to the peer. +* snb\_b2b\_usd\_bar2\_addr64 - If using B2B topology on Xeon hardware, use this + 64 bit address on the bus between the NTB devices for the window at + BAR2, on the upstream side of the link. +* snb\_b2b\_usd\_bar4\_addr64 - See *snb\_b2b\_bar2\_addr64*. +* snb\_b2b\_usd\_bar4\_addr32 - See *snb\_b2b\_bar2\_addr64*. +* snb\_b2b\_usd\_bar5\_addr32 - See *snb\_b2b\_bar2\_addr64*. +* snb\_b2b\_dsd\_bar2\_addr64 - See *snb\_b2b\_bar2\_addr64*. +* snb\_b2b\_dsd\_bar4\_addr64 - See *snb\_b2b\_bar2\_addr64*. +* snb\_b2b\_dsd\_bar4\_addr32 - See *snb\_b2b\_bar2\_addr64*. +* snb\_b2b\_dsd\_bar5\_addr32 - See *snb\_b2b\_bar2\_addr64*. diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c index 499222285439..c5ad7cb1706d 100644 --- a/drivers/ntb/hw/intel/ntb_hw_intel.c +++ b/drivers/ntb/hw/intel/ntb_hw_intel.c @@ -72,20 +72,6 @@ MODULE_AUTHOR("Intel Corporation"); #define bar0_off(base, bar) ((base) + ((bar) << 2)) #define bar2_off(base, bar) bar0_off(base, (bar) - 2) -static int b2b_mw_idx = -1; -module_param(b2b_mw_idx, int, 0644); -MODULE_PARM_DESC(b2b_mw_idx, "Use this mw idx to access the peer ntb. A " - "value of zero or positive starts from first mw idx, and a " - "negative value starts from last mw idx. Both sides MUST " - "set the same value here!"); - -static unsigned int b2b_mw_share; -module_param(b2b_mw_share, uint, 0644); -MODULE_PARM_DESC(b2b_mw_share, "If the b2b mw is large enough, configure the " - "ntb so that the peer ntb only occupies the first half of " - "the mw, so the second half can still be used as a mw. Both " - "sides MUST set the same value here!"); - static const struct intel_ntb_reg bwd_reg; static const struct intel_ntb_alt_reg bwd_pri_reg; static const struct intel_ntb_alt_reg bwd_sec_reg; @@ -98,14 +84,67 @@ static const struct intel_ntb_alt_reg snb_sec_reg; static const struct intel_ntb_alt_reg snb_b2b_reg; static const struct intel_ntb_xlat_reg snb_pri_xlat; static const struct intel_ntb_xlat_reg snb_sec_xlat; -static const struct intel_b2b_addr snb_b2b_usd_addr; -static const struct intel_b2b_addr snb_b2b_dsd_addr; - +static struct intel_b2b_addr snb_b2b_usd_addr; +static struct intel_b2b_addr snb_b2b_dsd_addr; static const struct ntb_dev_ops intel_ntb_ops; static const struct file_operations intel_ntb_debugfs_info; static struct dentry *debugfs_dir; +static int b2b_mw_idx = -1; +module_param(b2b_mw_idx, int, 0644); +MODULE_PARM_DESC(b2b_mw_idx, "Use this mw idx to access the peer ntb. A " + "value of zero or positive starts from first mw idx, and a " + "negative value starts from last mw idx. Both sides MUST " + "set the same value here!"); + +static unsigned int b2b_mw_share; +module_param(b2b_mw_share, uint, 0644); +MODULE_PARM_DESC(b2b_mw_share, "If the b2b mw is large enough, configure the " + "ntb so that the peer ntb only occupies the first half of " + "the mw, so the second half can still be used as a mw. Both " + "sides MUST set the same value here!"); + +module_param_named(snb_b2b_usd_bar2_addr64, + snb_b2b_usd_addr.bar2_addr64, ullong, 0644); +MODULE_PARM_DESC(snb_b2b_usd_bar2_addr64, + "SNB B2B USD BAR 2 64-bit address"); + +module_param_named(snb_b2b_usd_bar4_addr64, + snb_b2b_usd_addr.bar4_addr64, ullong, 0644); +MODULE_PARM_DESC(snb_b2b_usd_bar2_addr64, + "SNB B2B USD BAR 4 64-bit address"); + +module_param_named(snb_b2b_usd_bar4_addr32, + snb_b2b_usd_addr.bar4_addr32, ullong, 0644); +MODULE_PARM_DESC(snb_b2b_usd_bar2_addr64, + "SNB B2B USD split-BAR 4 32-bit address"); + +module_param_named(snb_b2b_usd_bar5_addr32, + snb_b2b_usd_addr.bar5_addr32, ullong, 0644); +MODULE_PARM_DESC(snb_b2b_usd_bar2_addr64, + "SNB B2B USD split-BAR 5 32-bit address"); + +module_param_named(snb_b2b_dsd_bar2_addr64, + snb_b2b_dsd_addr.bar2_addr64, ullong, 0644); +MODULE_PARM_DESC(snb_b2b_dsd_bar2_addr64, + "SNB B2B DSD BAR 2 64-bit address"); + +module_param_named(snb_b2b_dsd_bar4_addr64, + snb_b2b_dsd_addr.bar4_addr64, ullong, 0644); +MODULE_PARM_DESC(snb_b2b_dsd_bar2_addr64, + "SNB B2B DSD BAR 4 64-bit address"); + +module_param_named(snb_b2b_dsd_bar4_addr32, + snb_b2b_dsd_addr.bar4_addr32, ullong, 0644); +MODULE_PARM_DESC(snb_b2b_dsd_bar2_addr64, + "SNB B2B DSD split-BAR 4 32-bit address"); + +module_param_named(snb_b2b_dsd_bar5_addr32, + snb_b2b_dsd_addr.bar5_addr32, ullong, 0644); +MODULE_PARM_DESC(snb_b2b_dsd_bar2_addr64, + "SNB B2B DSD split-BAR 5 32-bit address"); + #ifndef ioread64 #ifdef readq #define ioread64 readq @@ -2073,14 +2112,14 @@ static const struct intel_ntb_xlat_reg snb_sec_xlat = { .bar2_xlat = SNB_SBAR23XLAT_OFFSET, }; -static const struct intel_b2b_addr snb_b2b_usd_addr = { +static struct intel_b2b_addr snb_b2b_usd_addr = { .bar2_addr64 = SNB_B2B_BAR2_USD_ADDR64, .bar4_addr64 = SNB_B2B_BAR4_USD_ADDR64, .bar4_addr32 = SNB_B2B_BAR4_USD_ADDR32, .bar5_addr32 = SNB_B2B_BAR5_USD_ADDR32, }; -static const struct intel_b2b_addr snb_b2b_dsd_addr = { +static struct intel_b2b_addr snb_b2b_dsd_addr = { .bar2_addr64 = SNB_B2B_BAR2_DSD_ADDR64, .bar4_addr64 = SNB_B2B_BAR4_DSD_ADDR64, .bar4_addr32 = SNB_B2B_BAR4_DSD_ADDR32, -- cgit v1.2.3-70-g09d2 From 963de4739fb4f8fa8d5cd87969109a7d3282ed13 Mon Sep 17 00:00:00 2001 From: Allen Hubbe Date: Wed, 15 Apr 2015 11:12:41 -0400 Subject: NTB: Add ping pong test client This is a simple ping pong driver that exercises the scratch pads and doorbells of the ntb hardware. This driver may be used to test that your ntb hardware and drivers are functioning at a basic level. Signed-off-by: Allen Hubbe Signed-off-by: Jon Mason --- Documentation/ntb.txt | 27 +++++ drivers/ntb/Kconfig | 2 + drivers/ntb/Makefile | 2 +- drivers/ntb/test/Kconfig | 8 ++ drivers/ntb/test/Makefile | 1 + drivers/ntb/test/ntb_pingpong.c | 250 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 289 insertions(+), 1 deletion(-) create mode 100644 drivers/ntb/test/Kconfig create mode 100644 drivers/ntb/test/Makefile create mode 100644 drivers/ntb/test/ntb_pingpong.c (limited to 'drivers') diff --git a/Documentation/ntb.txt b/Documentation/ntb.txt index 00a3f92832a5..e5d1591478ca 100644 --- a/Documentation/ntb.txt +++ b/Documentation/ntb.txt @@ -37,6 +37,33 @@ Transport queue pair. Network data is copied between socket buffers and the Transport queue pair buffer. The Transport client may be used for other things besides Netdev, however no other applications have yet been written. +### NTB Ping Pong Test Client (ntb\_pingpong) + +The Ping Pong test client serves as a demonstration to exercise the doorbell +and scratchpad registers of NTB hardware, and as an example simple NTB client. +Ping Pong enables the link when started, waits for the NTB link to come up, and +then proceeds to read and write the doorbell scratchpad registers of the NTB. +The peers interrupt each other using a bit mask of doorbell bits, which is +shifted by one in each round, to test the behavior of multiple doorbell bits +and interrupt vectors. The Ping Pong driver also reads the first local +scratchpad, and writes the value plus one to the first peer scratchpad, each +round before writing the peer doorbell register. + +Module Parameters: + +* unsafe - Some hardware has known issues with scratchpad and doorbell + registers. By default, Ping Pong will not attempt to exercise such + hardware. You may override this behavior at your own risk by setting + unsafe=1. +* delay\_ms - Specify the delay between receiving a doorbell + interrupt event and setting the peer doorbell register for the next + round. +* init\_db - Specify the doorbell bits to start new series of rounds. A new + series begins once all the doorbell bits have been shifted out of + range. +* dyndbg - It is suggested to specify dyndbg=+p when loading this module, and + then to observe debugging output on the console. + ## NTB Hardware Drivers NTB hardware drivers should register devices with the NTB core driver. After diff --git a/drivers/ntb/Kconfig b/drivers/ntb/Kconfig index 53b042429673..95944e52fa36 100644 --- a/drivers/ntb/Kconfig +++ b/drivers/ntb/Kconfig @@ -14,6 +14,8 @@ if NTB source "drivers/ntb/hw/Kconfig" +source "drivers/ntb/test/Kconfig" + config NTB_TRANSPORT tristate "NTB Transport Client" help diff --git a/drivers/ntb/Makefile b/drivers/ntb/Makefile index b9fa663ecfec..1921dec1949d 100644 --- a/drivers/ntb/Makefile +++ b/drivers/ntb/Makefile @@ -1,2 +1,2 @@ -obj-$(CONFIG_NTB) += ntb.o hw/ +obj-$(CONFIG_NTB) += ntb.o hw/ test/ obj-$(CONFIG_NTB_TRANSPORT) += ntb_transport.o diff --git a/drivers/ntb/test/Kconfig b/drivers/ntb/test/Kconfig new file mode 100644 index 000000000000..72d255d220c8 --- /dev/null +++ b/drivers/ntb/test/Kconfig @@ -0,0 +1,8 @@ +config NTB_PINGPONG + tristate "NTB Ping Pong Test Client" + help + This is a simple ping pong driver that exercises the scratchpads and + doorbells of the ntb hardware. This driver may be used to test that + your ntb hardware and drivers are functioning at a basic level. + + If unsure, say N. diff --git a/drivers/ntb/test/Makefile b/drivers/ntb/test/Makefile new file mode 100644 index 000000000000..b32309307771 --- /dev/null +++ b/drivers/ntb/test/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_NTB_PINGPONG) += ntb_pingpong.o diff --git a/drivers/ntb/test/ntb_pingpong.c b/drivers/ntb/test/ntb_pingpong.c new file mode 100644 index 000000000000..fe1600566981 --- /dev/null +++ b/drivers/ntb/test/ntb_pingpong.c @@ -0,0 +1,250 @@ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright (C) 2015 EMC Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright (C) 2015 EMC Corporation. 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 copy + * 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. + * + * PCIe NTB Pingpong Linux driver + * + * Contact Information: + * Allen Hubbe + */ + +/* Note: load this module with option 'dyndbg=+p' */ + +#include +#include +#include + +#include +#include +#include +#include + +#include + +#define DRIVER_NAME "ntb_pingpong" +#define DRIVER_DESCRIPTION "PCIe NTB Simple Pingpong Client" + +#define DRIVER_LICENSE "Dual BSD/GPL" +#define DRIVER_VERSION "1.0" +#define DRIVER_RELDATE "24 March 2015" +#define DRIVER_AUTHOR "Allen Hubbe " + +MODULE_LICENSE(DRIVER_LICENSE); +MODULE_VERSION(DRIVER_VERSION); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESCRIPTION); + +static unsigned int unsafe; +module_param(unsafe, uint, 0644); +MODULE_PARM_DESC(unsafe, "Run even though ntb operations may be unsafe"); + +static unsigned int delay_ms = 1000; +module_param(delay_ms, uint, 0644); +MODULE_PARM_DESC(delay_ms, "Milliseconds to delay the response to peer"); + +static unsigned long db_init = 0x7; +module_param(db_init, ulong, 0644); +MODULE_PARM_DESC(delay_ms, "Initial doorbell bits to ring on the peer"); + +struct pp_ctx { + struct ntb_dev *ntb; + u64 db_bits; + /* synchronize access to db_bits by ping and pong */ + spinlock_t db_lock; + struct timer_list db_timer; + unsigned long db_delay; +}; + +static void pp_ping(unsigned long ctx) +{ + struct pp_ctx *pp = (void *)ctx; + unsigned long irqflags; + u64 db_bits, db_mask; + u32 spad_rd, spad_wr; + + spin_lock_irqsave(&pp->db_lock, irqflags); + { + db_mask = ntb_db_valid_mask(pp->ntb); + db_bits = ntb_db_read(pp->ntb); + + if (db_bits) { + dev_dbg(&pp->ntb->dev, + "Masked pongs %#llx\n", + db_bits); + ntb_db_clear(pp->ntb, db_bits); + } + + db_bits = ((pp->db_bits | db_bits) << 1) & db_mask; + + if (!db_bits) + db_bits = db_init; + + spad_rd = ntb_spad_read(pp->ntb, 0); + spad_wr = spad_rd + 1; + + dev_dbg(&pp->ntb->dev, + "Ping bits %#llx read %#x write %#x\n", + db_bits, spad_rd, spad_wr); + + ntb_peer_spad_write(pp->ntb, 0, spad_wr); + ntb_peer_db_set(pp->ntb, db_bits); + ntb_db_clear_mask(pp->ntb, db_mask); + + pp->db_bits = 0; + } + spin_unlock_irqrestore(&pp->db_lock, irqflags); +} + +static void pp_link_event(void *ctx) +{ + struct pp_ctx *pp = ctx; + + if (ntb_link_is_up(pp->ntb, NULL, NULL) == 1) { + dev_dbg(&pp->ntb->dev, "link is up\n"); + pp_ping((unsigned long)pp); + } else { + dev_dbg(&pp->ntb->dev, "link is down\n"); + del_timer(&pp->db_timer); + } +} + +static void pp_db_event(void *ctx, int vec) +{ + struct pp_ctx *pp = ctx; + u64 db_bits, db_mask; + unsigned long irqflags; + + spin_lock_irqsave(&pp->db_lock, irqflags); + { + db_mask = ntb_db_vector_mask(pp->ntb, vec); + db_bits = db_mask & ntb_db_read(pp->ntb); + ntb_db_set_mask(pp->ntb, db_mask); + ntb_db_clear(pp->ntb, db_bits); + + pp->db_bits |= db_bits; + + mod_timer(&pp->db_timer, jiffies + pp->db_delay); + + dev_dbg(&pp->ntb->dev, + "Pong vec %d bits %#llx\n", + vec, db_bits); + } + spin_unlock_irqrestore(&pp->db_lock, irqflags); +} + +static const struct ntb_ctx_ops pp_ops = { + .link_event = pp_link_event, + .db_event = pp_db_event, +}; + +static int pp_probe(struct ntb_client *client, + struct ntb_dev *ntb) +{ + struct pp_ctx *pp; + int rc; + + if (ntb_db_is_unsafe(ntb)) { + dev_dbg(&ntb->dev, "doorbell is unsafe\n"); + if (!unsafe) { + rc = -EINVAL; + goto err_pp; + } + } + + if (ntb_spad_is_unsafe(ntb)) { + dev_dbg(&ntb->dev, "scratchpad is unsafe\n"); + if (!unsafe) { + rc = -EINVAL; + goto err_pp; + } + } + + pp = kmalloc(sizeof(*pp), GFP_KERNEL); + if (!pp) { + rc = -ENOMEM; + goto err_pp; + } + + pp->ntb = ntb; + pp->db_bits = 0; + spin_lock_init(&pp->db_lock); + setup_timer(&pp->db_timer, pp_ping, (unsigned long)pp); + pp->db_delay = msecs_to_jiffies(delay_ms); + + rc = ntb_set_ctx(ntb, pp, &pp_ops); + if (rc) + goto err_ctx; + + ntb_link_enable(ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO); + ntb_link_event(ntb); + + return 0; + +err_ctx: + kfree(pp); +err_pp: + return rc; +} + +static void pp_remove(struct ntb_client *client, + struct ntb_dev *ntb) +{ + struct pp_ctx *pp = ntb->ctx; + + ntb_clear_ctx(ntb); + del_timer_sync(&pp->db_timer); + ntb_link_disable(ntb); + + kfree(pp); +} + +static struct ntb_client pp_client = { + .ops = { + .probe = pp_probe, + .remove = pp_remove, + }, +}; +module_ntb_client(pp_client); -- cgit v1.2.3-70-g09d2 From 578b881ba9c4b253482903bf8fae438318f5629b Mon Sep 17 00:00:00 2001 From: Allen Hubbe Date: Thu, 21 May 2015 02:51:39 -0400 Subject: NTB: Add tool test client This is a simple debugging driver that enables the doorbell and scratch pad registers to be read and written from the debugfs. This tool enables more complicated debugging to be scripted from user space. This driver may be used to test that your ntb hardware and drivers are functioning at a basic level. Signed-off-by: Allen Hubbe Signed-off-by: Jon Mason --- Documentation/ntb.txt | 32 +++ drivers/ntb/test/Kconfig | 11 + drivers/ntb/test/Makefile | 1 + drivers/ntb/test/ntb_tool.c | 556 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 600 insertions(+) create mode 100644 drivers/ntb/test/ntb_tool.c (limited to 'drivers') diff --git a/Documentation/ntb.txt b/Documentation/ntb.txt index e5d1591478ca..b48249a7b607 100644 --- a/Documentation/ntb.txt +++ b/Documentation/ntb.txt @@ -64,6 +64,38 @@ Module Parameters: * dyndbg - It is suggested to specify dyndbg=+p when loading this module, and then to observe debugging output on the console. +### NTB Tool Test Client (ntb\_tool) + +The Tool test client serves for debugging, primarily, ntb hardware and drivers. +The Tool provides access through debugfs for reading, setting, and clearing the +NTB doorbell, and reading and writing scratchpads. + +The Tool does not currently have any module parameters. + +Debugfs Files: + +* *debugfs*/ntb\_tool/*hw*/ - A directory in debugfs will be created for each + NTB device probed by the tool. This directory is shortened to *hw* + below. +* *hw*/db - This file is used to read, set, and clear the local doorbell. Not + all operations may be supported by all hardware. To read the doorbell, + read the file. To set the doorbell, write `s` followed by the bits to + set (eg: `echo 's 0x0101' > db`). To clear the doorbell, write `c` + followed by the bits to clear. +* *hw*/mask - This file is used to read, set, and clear the local doorbell mask. + See *db* for details. +* *hw*/peer\_db - This file is used to read, set, and clear the peer doorbell. + See *db* for details. +* *hw*/peer\_mask - This file is used to read, set, and clear the peer doorbell + mask. See *db* for details. +* *hw*/spad - This file is used to read and write local scratchpads. To read + the values of all scratchpads, read the file. To write values, write a + series of pairs of scratchpad number and value + (eg: `echo '4 0x123 7 0xabc' > spad` + # to set scratchpads `4` and `7` to `0x123` and `0xabc`, respectively). +* *hw*/peer\_spad - This file is used to read and write peer scratchpads. See + *spad* for details. + ## NTB Hardware Drivers NTB hardware drivers should register devices with the NTB core driver. After diff --git a/drivers/ntb/test/Kconfig b/drivers/ntb/test/Kconfig index 72d255d220c8..01852f98a843 100644 --- a/drivers/ntb/test/Kconfig +++ b/drivers/ntb/test/Kconfig @@ -6,3 +6,14 @@ config NTB_PINGPONG your ntb hardware and drivers are functioning at a basic level. If unsure, say N. + +config NTB_TOOL + tristate "NTB Debugging Tool Test Client" + help + This is a simple debugging driver that enables the doorbell and + scratchpad registers to be read and written from the debugfs. This + enables more complicated debugging to be scripted from user space. + This driver may be used to test that your ntb hardware and drivers are + functioning at a basic level. + + If unsure, say N. diff --git a/drivers/ntb/test/Makefile b/drivers/ntb/test/Makefile index b32309307771..0ea32a324b6c 100644 --- a/drivers/ntb/test/Makefile +++ b/drivers/ntb/test/Makefile @@ -1 +1,2 @@ obj-$(CONFIG_NTB_PINGPONG) += ntb_pingpong.o +obj-$(CONFIG_NTB_TOOL) += ntb_tool.o diff --git a/drivers/ntb/test/ntb_tool.c b/drivers/ntb/test/ntb_tool.c new file mode 100644 index 000000000000..6f5dc6ca673d --- /dev/null +++ b/drivers/ntb/test/ntb_tool.c @@ -0,0 +1,556 @@ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright (C) 2015 EMC Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright (C) 2015 EMC Corporation. 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 copy + * 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. + * + * PCIe NTB Debugging Tool Linux driver + * + * Contact Information: + * Allen Hubbe + */ + +/* + * How to use this tool, by example. + * + * Assuming $DBG_DIR is something like: + * '/sys/kernel/debug/ntb_tool/0000:00:03.0' + * + * Eg: check if clearing the doorbell mask generates an interrupt. + * + * # Set the doorbell mask + * root@self# echo 's 1' > $DBG_DIR/mask + * + * # Ring the doorbell from the peer + * root@peer# echo 's 1' > $DBG_DIR/peer_db + * + * # Clear the doorbell mask + * root@self# echo 'c 1' > $DBG_DIR/mask + * + * Observe debugging output in dmesg or your console. You should see a + * doorbell event triggered by clearing the mask. If not, this may indicate an + * issue with the hardware that needs to be worked around in the driver. + * + * Eg: read and write scratchpad registers + * + * root@peer# echo '0 0x01010101 1 0x7f7f7f7f' > $DBG_DIR/peer_spad + * + * root@self# cat $DBG_DIR/spad + * + * Observe that spad 0 and 1 have the values set by the peer. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include + +#define DRIVER_NAME "ntb_tool" +#define DRIVER_DESCRIPTION "PCIe NTB Debugging Tool" + +#define DRIVER_LICENSE "Dual BSD/GPL" +#define DRIVER_VERSION "1.0" +#define DRIVER_RELDATE "22 April 2015" +#define DRIVER_AUTHOR "Allen Hubbe " + +MODULE_LICENSE(DRIVER_LICENSE); +MODULE_VERSION(DRIVER_VERSION); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESCRIPTION); + +static struct dentry *tool_dbgfs; + +struct tool_ctx { + struct ntb_dev *ntb; + struct dentry *dbgfs; +}; + +#define SPAD_FNAME_SIZE 0x10 +#define INT_PTR(x) ((void *)(unsigned long)x) +#define PTR_INT(x) ((int)(unsigned long)x) + +#define TOOL_FOPS_RDWR(__name, __read, __write) \ + const struct file_operations __name = { \ + .owner = THIS_MODULE, \ + .open = simple_open, \ + .read = __read, \ + .write = __write, \ + } + +static void tool_link_event(void *ctx) +{ + struct tool_ctx *tc = ctx; + enum ntb_speed speed; + enum ntb_width width; + int up; + + up = ntb_link_is_up(tc->ntb, &speed, &width); + + dev_dbg(&tc->ntb->dev, "link is %s speed %d width %d\n", + up ? "up" : "down", speed, width); +} + +static void tool_db_event(void *ctx, int vec) +{ + struct tool_ctx *tc = ctx; + u64 db_bits, db_mask; + + db_mask = ntb_db_vector_mask(tc->ntb, vec); + db_bits = ntb_db_read(tc->ntb); + + dev_dbg(&tc->ntb->dev, "doorbell vec %d mask %#llx bits %#llx\n", + vec, db_mask, db_bits); +} + +static const struct ntb_ctx_ops tool_ops = { + .link_event = tool_link_event, + .db_event = tool_db_event, +}; + +static ssize_t tool_dbfn_read(struct tool_ctx *tc, char __user *ubuf, + size_t size, loff_t *offp, + u64 (*db_read_fn)(struct ntb_dev *)) +{ + size_t buf_size; + char *buf; + ssize_t pos, rc; + + if (!db_read_fn) + return -EINVAL; + + buf_size = min_t(size_t, size, 0x20); + + buf = kmalloc(buf_size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + pos = scnprintf(buf, buf_size, "%#llx\n", + db_read_fn(tc->ntb)); + + rc = simple_read_from_buffer(ubuf, size, offp, buf, pos); + + kfree(buf); + + return rc; +} + +static ssize_t tool_dbfn_write(struct tool_ctx *tc, + const char __user *ubuf, + size_t size, loff_t *offp, + int (*db_set_fn)(struct ntb_dev *, u64), + int (*db_clear_fn)(struct ntb_dev *, u64)) +{ + u64 db_bits; + char *buf, cmd; + ssize_t rc; + int n; + + buf = kmalloc(size + 1, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + rc = simple_write_to_buffer(buf, size, offp, ubuf, size); + if (rc < 0) { + kfree(buf); + return rc; + } + + buf[size] = 0; + + n = sscanf(buf, "%c %lli", &cmd, &db_bits); + + kfree(buf); + + if (n != 2) { + rc = -EINVAL; + } else if (cmd == 's') { + if (!db_set_fn) + rc = -EINVAL; + else + rc = db_set_fn(tc->ntb, db_bits); + } else if (cmd == 'c') { + if (!db_clear_fn) + rc = -EINVAL; + else + rc = db_clear_fn(tc->ntb, db_bits); + } else { + rc = -EINVAL; + } + + return rc ? : size; +} + +static ssize_t tool_spadfn_read(struct tool_ctx *tc, char __user *ubuf, + size_t size, loff_t *offp, + u32 (*spad_read_fn)(struct ntb_dev *, int)) +{ + size_t buf_size; + char *buf; + ssize_t pos, rc; + int i, spad_count; + + if (!spad_read_fn) + return -EINVAL; + + buf_size = min_t(size_t, size, 0x100); + + buf = kmalloc(buf_size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + pos = 0; + + spad_count = ntb_spad_count(tc->ntb); + for (i = 0; i < spad_count; ++i) { + pos += scnprintf(buf + pos, buf_size - pos, "%d\t%#x\n", + i, spad_read_fn(tc->ntb, i)); + } + + rc = simple_read_from_buffer(ubuf, size, offp, buf, pos); + + kfree(buf); + + return rc; +} + +static ssize_t tool_spadfn_write(struct tool_ctx *tc, + const char __user *ubuf, + size_t size, loff_t *offp, + int (*spad_write_fn)(struct ntb_dev *, + int, u32)) +{ + int spad_idx; + u32 spad_val; + char *buf; + int pos, n; + ssize_t rc; + + if (!spad_write_fn) { + dev_dbg(&tc->ntb->dev, "no spad write fn\n"); + return -EINVAL; + } + + buf = kmalloc(size + 1, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + rc = simple_write_to_buffer(buf, size, offp, ubuf, size); + if (rc < 0) { + kfree(buf); + return rc; + } + + buf[size] = 0; + + n = sscanf(buf, "%d %i%n", &spad_idx, &spad_val, &pos); + while (n == 2) { + rc = spad_write_fn(tc->ntb, spad_idx, spad_val); + if (rc) + break; + + n = sscanf(buf + pos, "%d %i%n", &spad_idx, &spad_val, &pos); + } + + if (n < 0) + rc = n; + + kfree(buf); + + return rc ? : size; +} + +static ssize_t tool_db_read(struct file *filep, char __user *ubuf, + size_t size, loff_t *offp) +{ + struct tool_ctx *tc = filep->private_data; + + return tool_dbfn_read(tc, ubuf, size, offp, + tc->ntb->ops->db_read); +} + +static ssize_t tool_db_write(struct file *filep, const char __user *ubuf, + size_t size, loff_t *offp) +{ + struct tool_ctx *tc = filep->private_data; + + return tool_dbfn_write(tc, ubuf, size, offp, + tc->ntb->ops->db_set, + tc->ntb->ops->db_clear); +} + +static TOOL_FOPS_RDWR(tool_db_fops, + tool_db_read, + tool_db_write); + +static ssize_t tool_mask_read(struct file *filep, char __user *ubuf, + size_t size, loff_t *offp) +{ + struct tool_ctx *tc = filep->private_data; + + return tool_dbfn_read(tc, ubuf, size, offp, + tc->ntb->ops->db_read_mask); +} + +static ssize_t tool_mask_write(struct file *filep, const char __user *ubuf, + size_t size, loff_t *offp) +{ + struct tool_ctx *tc = filep->private_data; + + return tool_dbfn_write(tc, ubuf, size, offp, + tc->ntb->ops->db_set_mask, + tc->ntb->ops->db_clear_mask); +} + +static TOOL_FOPS_RDWR(tool_mask_fops, + tool_mask_read, + tool_mask_write); + +static ssize_t tool_peer_db_read(struct file *filep, char __user *ubuf, + size_t size, loff_t *offp) +{ + struct tool_ctx *tc = filep->private_data; + + return tool_dbfn_read(tc, ubuf, size, offp, + tc->ntb->ops->peer_db_read); +} + +static ssize_t tool_peer_db_write(struct file *filep, const char __user *ubuf, + size_t size, loff_t *offp) +{ + struct tool_ctx *tc = filep->private_data; + + return tool_dbfn_write(tc, ubuf, size, offp, + tc->ntb->ops->peer_db_set, + tc->ntb->ops->peer_db_clear); +} + +static TOOL_FOPS_RDWR(tool_peer_db_fops, + tool_peer_db_read, + tool_peer_db_write); + +static ssize_t tool_peer_mask_read(struct file *filep, char __user *ubuf, + size_t size, loff_t *offp) +{ + struct tool_ctx *tc = filep->private_data; + + return tool_dbfn_read(tc, ubuf, size, offp, + tc->ntb->ops->peer_db_read_mask); +} + +static ssize_t tool_peer_mask_write(struct file *filep, const char __user *ubuf, + size_t size, loff_t *offp) +{ + struct tool_ctx *tc = filep->private_data; + + return tool_dbfn_write(tc, ubuf, size, offp, + tc->ntb->ops->peer_db_set_mask, + tc->ntb->ops->peer_db_clear_mask); +} + +static TOOL_FOPS_RDWR(tool_peer_mask_fops, + tool_peer_mask_read, + tool_peer_mask_write); + +static ssize_t tool_spad_read(struct file *filep, char __user *ubuf, + size_t size, loff_t *offp) +{ + struct tool_ctx *tc = filep->private_data; + + return tool_spadfn_read(tc, ubuf, size, offp, + tc->ntb->ops->spad_read); +} + +static ssize_t tool_spad_write(struct file *filep, const char __user *ubuf, + size_t size, loff_t *offp) +{ + struct tool_ctx *tc = filep->private_data; + + return tool_spadfn_write(tc, ubuf, size, offp, + tc->ntb->ops->spad_write); +} + +static TOOL_FOPS_RDWR(tool_spad_fops, + tool_spad_read, + tool_spad_write); + +static ssize_t tool_peer_spad_read(struct file *filep, char __user *ubuf, + size_t size, loff_t *offp) +{ + struct tool_ctx *tc = filep->private_data; + + return tool_spadfn_read(tc, ubuf, size, offp, + tc->ntb->ops->peer_spad_read); +} + +static ssize_t tool_peer_spad_write(struct file *filep, const char __user *ubuf, + size_t size, loff_t *offp) +{ + struct tool_ctx *tc = filep->private_data; + + return tool_spadfn_write(tc, ubuf, size, offp, + tc->ntb->ops->peer_spad_write); +} + +static TOOL_FOPS_RDWR(tool_peer_spad_fops, + tool_peer_spad_read, + tool_peer_spad_write); + +static void tool_setup_dbgfs(struct tool_ctx *tc) +{ + /* This modules is useless without dbgfs... */ + if (!tool_dbgfs) { + tc->dbgfs = NULL; + return; + } + + tc->dbgfs = debugfs_create_dir(dev_name(&tc->ntb->dev), + tool_dbgfs); + if (!tc->dbgfs) + return; + + debugfs_create_file("db", S_IRUSR | S_IWUSR, tc->dbgfs, + tc, &tool_db_fops); + + debugfs_create_file("mask", S_IRUSR | S_IWUSR, tc->dbgfs, + tc, &tool_mask_fops); + + debugfs_create_file("peer_db", S_IRUSR | S_IWUSR, tc->dbgfs, + tc, &tool_peer_db_fops); + + debugfs_create_file("peer_mask", S_IRUSR | S_IWUSR, tc->dbgfs, + tc, &tool_peer_mask_fops); + + debugfs_create_file("spad", S_IRUSR | S_IWUSR, tc->dbgfs, + tc, &tool_spad_fops); + + debugfs_create_file("peer_spad", S_IRUSR | S_IWUSR, tc->dbgfs, + tc, &tool_peer_spad_fops); +} + +static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb) +{ + struct tool_ctx *tc; + int rc; + + if (ntb_db_is_unsafe(ntb)) + dev_dbg(&ntb->dev, "doorbell is unsafe\n"); + + if (ntb_spad_is_unsafe(ntb)) + dev_dbg(&ntb->dev, "scratchpad is unsafe\n"); + + tc = kmalloc(sizeof(*tc), GFP_KERNEL); + if (!tc) { + rc = -ENOMEM; + goto err_tc; + } + + tc->ntb = ntb; + + tool_setup_dbgfs(tc); + + rc = ntb_set_ctx(ntb, tc, &tool_ops); + if (rc) + goto err_ctx; + + ntb_link_enable(ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO); + ntb_link_event(ntb); + + return 0; + +err_ctx: + debugfs_remove_recursive(tc->dbgfs); + kfree(tc); +err_tc: + return rc; +} + +static void tool_remove(struct ntb_client *self, struct ntb_dev *ntb) +{ + struct tool_ctx *tc = ntb->ctx; + + ntb_clear_ctx(ntb); + ntb_link_disable(ntb); + + debugfs_remove_recursive(tc->dbgfs); + kfree(tc); +} + +static struct ntb_client tool_client = { + .ops = { + .probe = tool_probe, + .remove = tool_remove, + }, +}; + +static int __init tool_init(void) +{ + int rc; + + if (debugfs_initialized()) + tool_dbgfs = debugfs_create_dir(KBUILD_MODNAME, NULL); + + rc = ntb_register_client(&tool_client); + if (rc) + goto err_client; + + return 0; + +err_client: + debugfs_remove_recursive(tool_dbgfs); + return rc; +} +module_init(tool_init); + +static void __exit tool_exit(void) +{ + ntb_unregister_client(&tool_client); + debugfs_remove_recursive(tool_dbgfs); +} +module_exit(tool_exit); -- cgit v1.2.3-70-g09d2 From 2876228941ac5dcab12854aa5a3462b3f2274b09 Mon Sep 17 00:00:00 2001 From: Allen Hubbe Date: Mon, 11 May 2015 10:08:26 -0400 Subject: NTB: Rate limit ntb_qp_link_work When the ntb transport is connecting and waiting for the peer, the debug console receives lots of debug level messages about the remote qp link status being down. Rate limit those messages. Signed-off-by: Allen Hubbe Signed-off-by: Jon Mason --- drivers/ntb/ntb_transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index 2efd1eae9a7c..8ce0bf67ac20 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c @@ -850,7 +850,7 @@ static void ntb_qp_link_work(struct work_struct *work) /* query remote spad for qp ready bits */ ntb_peer_spad_read(nt->ndev, QP_LINKS); - dev_dbg(&pdev->dev, "Remote QP link status = %x\n", val); + dev_dbg_ratelimited(&pdev->dev, "Remote QP link status = %x\n", val); /* See if the remote side is up */ if (val & BIT(qp->qp_num)) { -- cgit v1.2.3-70-g09d2 From 1199aa61264a74717bc747e7031673242bad5119 Mon Sep 17 00:00:00 2001 From: Allen Hubbe Date: Mon, 18 May 2015 06:20:47 -0400 Subject: NTB: Use NUMA memory and DMA chan in transport Allocate memory and request the DMA channel for the same NUMA node as the NTB device. Signed-off-by: Allen Hubbe Signed-off-by: Jon Mason --- drivers/ntb/ntb_transport.c | 46 +++++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index 8ce0bf67ac20..dc14ec81c43e 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c @@ -346,6 +346,7 @@ int ntb_transport_register_client_dev(char *device_name) { struct ntb_transport_client_dev *client_dev; struct ntb_transport_ctx *nt; + int node; int rc, i = 0; if (list_empty(&ntb_transport_list)) @@ -354,8 +355,10 @@ int ntb_transport_register_client_dev(char *device_name) list_for_each_entry(nt, &ntb_transport_list, entry) { struct device *dev; - client_dev = kzalloc(sizeof(*client_dev), - GFP_KERNEL); + node = dev_to_node(&nt->ndev->dev); + + client_dev = kzalloc_node(sizeof(*client_dev), + GFP_KERNEL, node); if (!client_dev) { rc = -ENOMEM; goto err; @@ -953,6 +956,7 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev) struct ntb_transport_mw *mw; unsigned int mw_count, qp_count; u64 qp_bitmap; + int node; int rc, i; if (ntb_db_is_unsafe(ndev)) @@ -962,7 +966,9 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev) dev_dbg(&ndev->dev, "scratchpad is unsafe, proceed anyway...\n"); - nt = kzalloc(sizeof(*nt), GFP_KERNEL); + node = dev_to_node(&ndev->dev); + + nt = kzalloc_node(sizeof(*nt), GFP_KERNEL, node); if (!nt) return -ENOMEM; @@ -972,7 +978,8 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev) nt->mw_count = mw_count; - nt->mw_vec = kcalloc(mw_count, sizeof(*nt->mw_vec), GFP_KERNEL); + nt->mw_vec = kzalloc_node(mw_count * sizeof(*nt->mw_vec), + GFP_KERNEL, node); if (!nt->mw_vec) { rc = -ENOMEM; goto err; @@ -1012,7 +1019,8 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev) nt->qp_bitmap = qp_bitmap; nt->qp_bitmap_free = qp_bitmap; - nt->qp_vec = kcalloc(qp_count, sizeof(*nt->qp_vec), GFP_KERNEL); + nt->qp_vec = kzalloc_node(qp_count * sizeof(*nt->qp_vec), + GFP_KERNEL, node); if (!nt->qp_vec) { rc = -ENOMEM; goto err2; @@ -1512,6 +1520,11 @@ static void ntb_send_link_down(struct ntb_transport_qp *qp) ntb_qp_link_down_reset(qp); } +static bool ntb_dma_filter_fn(struct dma_chan *chan, void *node) +{ + return dev_to_node(&chan->dev->device) == (int)(unsigned long)node; +} + /** * ntb_transport_create_queue - Create a new NTB transport layer queue * @rx_handler: receive callback function @@ -1537,12 +1550,16 @@ ntb_transport_create_queue(void *data, struct device *client_dev, struct ntb_transport_qp *qp; u64 qp_bit; unsigned int free_queue; + dma_cap_mask_t dma_mask; + int node; int i; ndev = dev_ntb(client_dev->parent); pdev = ndev->pdev; nt = ndev->ctx; + node = dev_to_node(&ndev->dev); + free_queue = ffs(nt->qp_bitmap); if (!free_queue) goto err; @@ -1560,15 +1577,16 @@ ntb_transport_create_queue(void *data, struct device *client_dev, qp->tx_handler = handlers->tx_handler; qp->event_handler = handlers->event_handler; - dmaengine_get(); - qp->dma_chan = dma_find_channel(DMA_MEMCPY); - if (!qp->dma_chan) { - dmaengine_put(); + dma_cap_zero(dma_mask); + dma_cap_set(DMA_MEMCPY, dma_mask); + + qp->dma_chan = dma_request_channel(dma_mask, ntb_dma_filter_fn, + (void *)(unsigned long)node); + if (!qp->dma_chan) dev_info(&pdev->dev, "Unable to allocate DMA channel, using CPU instead\n"); - } for (i = 0; i < NTB_QP_DEF_NUM_ENTRIES; i++) { - entry = kzalloc(sizeof(*entry), GFP_ATOMIC); + entry = kzalloc_node(sizeof(*entry), GFP_ATOMIC, node); if (!entry) goto err1; @@ -1578,7 +1596,7 @@ ntb_transport_create_queue(void *data, struct device *client_dev, } for (i = 0; i < NTB_QP_DEF_NUM_ENTRIES; i++) { - entry = kzalloc(sizeof(*entry), GFP_ATOMIC); + entry = kzalloc_node(sizeof(*entry), GFP_ATOMIC, node); if (!entry) goto err2; @@ -1601,7 +1619,7 @@ err1: while ((entry = ntb_list_rm(&qp->ntb_rx_free_q_lock, &qp->rx_free_q))) kfree(entry); if (qp->dma_chan) - dmaengine_put(); + dma_release_channel(qp->dma_chan); nt->qp_bitmap_free |= qp_bit; err: return NULL; @@ -1638,7 +1656,7 @@ void ntb_transport_free_queue(struct ntb_transport_qp *qp) */ dma_sync_wait(chan, qp->last_cookie); dmaengine_terminate_all(chan); - dmaengine_put(); + dma_release_channel(chan); } qp_bit = BIT_ULL(qp->qp_num); -- cgit v1.2.3-70-g09d2 From 0e041fb5369975c183d22ffeb156ea0dae760088 Mon Sep 17 00:00:00 2001 From: Allen Hubbe Date: Tue, 19 May 2015 12:04:52 -0400 Subject: NTB: Use NUMA memory in Intel driver Allocate memory for the NUMA node of the NTB device. Signed-off-by: Allen Hubbe Signed-off-by: Jon Mason --- drivers/ntb/hw/intel/ntb_hw_intel.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c index c5ad7cb1706d..236b7d33b5af 100644 --- a/drivers/ntb/hw/intel/ntb_hw_intel.c +++ b/drivers/ntb/hw/intel/ntb_hw_intel.c @@ -413,10 +413,12 @@ static int ndev_init_isr(struct intel_ntb_dev *ndev, int msix_shift, int total_shift) { struct pci_dev *pdev; - int rc, i, msix_count; + int rc, i, msix_count, node; pdev = ndev_pdev(ndev); + node = dev_to_node(&pdev->dev); + /* Mask all doorbell interrupts */ ndev->db_mask = ndev->db_valid_mask; ndev->reg->db_iowrite(ndev->db_mask, @@ -425,11 +427,13 @@ static int ndev_init_isr(struct intel_ntb_dev *ndev, /* Try to set up msix irq */ - ndev->vec = kcalloc(msix_max, sizeof(*ndev->vec), GFP_KERNEL); + ndev->vec = kzalloc_node(msix_max * sizeof(*ndev->vec), + GFP_KERNEL, node); if (!ndev->vec) goto err_msix_vec_alloc; - ndev->msix = kcalloc(msix_max, sizeof(*ndev->msix), GFP_KERNEL); + ndev->msix = kzalloc_node(msix_max * sizeof(*ndev->msix), + GFP_KERNEL, node); if (!ndev->msix) goto err_msix_alloc; @@ -1955,10 +1959,12 @@ static int intel_ntb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct intel_ntb_dev *ndev; - int rc; + int rc, node; + + node = dev_to_node(&pdev->dev); if (pdev_is_bwd(pdev)) { - ndev = kzalloc(sizeof(*ndev), GFP_KERNEL); + ndev = kzalloc_node(sizeof(*ndev), GFP_KERNEL, node); if (!ndev) { rc = -ENOMEM; goto err_ndev; @@ -1975,7 +1981,7 @@ static int intel_ntb_pci_probe(struct pci_dev *pdev, goto err_init_dev; } else if (pdev_is_snb(pdev)) { - ndev = kzalloc(sizeof(*ndev), GFP_KERNEL); + ndev = kzalloc_node(sizeof(*ndev), GFP_KERNEL, node); if (!ndev) { rc = -ENOMEM; goto err_ndev; -- cgit v1.2.3-70-g09d2 From 06917f753547e6bba8a5d17f79971d1c071a70dd Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Tue, 19 May 2015 16:45:46 -0400 Subject: NTB: Improve performance with write combining Changing the memory window BAR mappings to write combining significantly boosts the performance. We will also use memcpy that uses non-temporal store, which showed performance improvement when doing non-cached memcpys. Signed-off-by: Dave Jiang Signed-off-by: Jon Mason --- drivers/ntb/ntb_transport.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index dc14ec81c43e..7a765d3230d8 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c @@ -58,6 +58,7 @@ #include #include #include +#include #include "linux/ntb.h" #include "linux/ntb_transport.h" @@ -993,7 +994,7 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev) if (rc) goto err1; - mw->vbase = ioremap(mw->phys_addr, mw->phys_size); + mw->vbase = ioremap_wc(mw->phys_addr, mw->phys_size); if (!mw->vbase) { rc = -ENOMEM; goto err1; @@ -1375,7 +1376,15 @@ static void ntb_tx_copy_callback(void *data) static void ntb_memcpy_tx(struct ntb_queue_entry *entry, void __iomem *offset) { +#ifdef ARCH_HAS_NOCACHE_UACCESS + /* + * Using non-temporal mov to improve performance on non-cached + * writes, even though we aren't actually copying from user space. + */ + __copy_from_user_inatomic_nocache(offset, entry->buf, entry->len); +#else memcpy_toio(offset, entry->buf, entry->len); +#endif /* Ensure that the data is fully copied out before setting the flags */ wmb(); -- cgit v1.2.3-70-g09d2 From a41ef053f700618f5f55a1dd658908a71163400b Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Tue, 19 May 2015 16:52:04 -0400 Subject: NTB: Default to CPU memcpy for performance Disable DMA usage by default, since the CPU provides much better performance with write combining. Provide a module parameter to enable DMA usage when offloading the memcpy is preferred. Signed-off-by: Dave Jiang Signed-off-by: Allen Hubbe Signed-off-by: Jon Mason --- drivers/ntb/ntb_transport.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index 7a765d3230d8..e07b056af3be 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c @@ -88,6 +88,10 @@ static unsigned int copy_bytes = 1024; module_param(copy_bytes, uint, 0644); MODULE_PARM_DESC(copy_bytes, "Threshold under which NTB will use the CPU to copy instead of DMA"); +static bool use_dma; +module_param(use_dma, bool, 0644); +MODULE_PARM_DESC(use_dma, "Use DMA engine to perform large data copy"); + static struct dentry *nt_debugfs_dir; struct ntb_queue_entry { @@ -1589,10 +1593,15 @@ ntb_transport_create_queue(void *data, struct device *client_dev, dma_cap_zero(dma_mask); dma_cap_set(DMA_MEMCPY, dma_mask); - qp->dma_chan = dma_request_channel(dma_mask, ntb_dma_filter_fn, - (void *)(unsigned long)node); - if (!qp->dma_chan) - dev_info(&pdev->dev, "Unable to allocate DMA channel, using CPU instead\n"); + if (use_dma) { + qp->dma_chan = dma_request_channel(dma_mask, ntb_dma_filter_fn, + (void *)(unsigned long)node); + if (!qp->dma_chan) + dev_info(&pdev->dev, "Unable to allocate DMA channel\n"); + } else { + qp->dma_chan = NULL; + } + dev_dbg(&pdev->dev, "Using %s memcpy\n", qp->dma_chan ? "DMA" : "CPU"); for (i = 0; i < NTB_QP_DEF_NUM_ENTRIES; i++) { entry = kzalloc_node(sizeof(*entry), GFP_ATOMIC, node); -- cgit v1.2.3-70-g09d2 From 2f887b9a44015a8146d52e40bef9e2b7bc6cd275 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Wed, 20 May 2015 12:55:47 -0400 Subject: NTB: Rename Intel code names to platform names Instead of using the platform code names, use the correct platform names to identify the respective Intel NTB hardware. Signed-off-by: Dave Jiang Signed-off-by: Jon Mason --- Documentation/ntb.txt | 20 +- drivers/ntb/hw/intel/ntb_hw_intel.c | 620 ++++++++++++++++++------------------ drivers/ntb/hw/intel/ntb_hw_intel.h | 290 ++++++++--------- 3 files changed, 465 insertions(+), 465 deletions(-) (limited to 'drivers') diff --git a/Documentation/ntb.txt b/Documentation/ntb.txt index b48249a7b607..1d9bbabb6c79 100644 --- a/Documentation/ntb.txt +++ b/Documentation/ntb.txt @@ -115,13 +115,13 @@ Module Parameters: * b2b\_mw\_share - If the peer ntb is to be accessed via a memory window, and if the memory window is large enough, still allow the client to use the second half of the memory window for address translation to the peer. -* snb\_b2b\_usd\_bar2\_addr64 - If using B2B topology on Xeon hardware, use this - 64 bit address on the bus between the NTB devices for the window at - BAR2, on the upstream side of the link. -* snb\_b2b\_usd\_bar4\_addr64 - See *snb\_b2b\_bar2\_addr64*. -* snb\_b2b\_usd\_bar4\_addr32 - See *snb\_b2b\_bar2\_addr64*. -* snb\_b2b\_usd\_bar5\_addr32 - See *snb\_b2b\_bar2\_addr64*. -* snb\_b2b\_dsd\_bar2\_addr64 - See *snb\_b2b\_bar2\_addr64*. -* snb\_b2b\_dsd\_bar4\_addr64 - See *snb\_b2b\_bar2\_addr64*. -* snb\_b2b\_dsd\_bar4\_addr32 - See *snb\_b2b\_bar2\_addr64*. -* snb\_b2b\_dsd\_bar5\_addr32 - See *snb\_b2b\_bar2\_addr64*. +* xeon\_b2b\_usd\_bar2\_addr64 - If using B2B topology on Xeon hardware, use + this 64 bit address on the bus between the NTB devices for the window + at BAR2, on the upstream side of the link. +* xeon\_b2b\_usd\_bar4\_addr64 - See *xeon\_b2b\_bar2\_addr64*. +* xeon\_b2b\_usd\_bar4\_addr32 - See *xeon\_b2b\_bar2\_addr64*. +* xeon\_b2b\_usd\_bar5\_addr32 - See *xeon\_b2b\_bar2\_addr64*. +* xeon\_b2b\_dsd\_bar2\_addr64 - See *xeon\_b2b\_bar2\_addr64*. +* xeon\_b2b\_dsd\_bar4\_addr64 - See *xeon\_b2b\_bar2\_addr64*. +* xeon\_b2b\_dsd\_bar4\_addr32 - See *xeon\_b2b\_bar2\_addr64*. +* xeon\_b2b\_dsd\_bar5\_addr32 - See *xeon\_b2b\_bar2\_addr64*. diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c index 236b7d33b5af..eeaa1e8f8bd8 100644 --- a/drivers/ntb/hw/intel/ntb_hw_intel.c +++ b/drivers/ntb/hw/intel/ntb_hw_intel.c @@ -72,20 +72,20 @@ MODULE_AUTHOR("Intel Corporation"); #define bar0_off(base, bar) ((base) + ((bar) << 2)) #define bar2_off(base, bar) bar0_off(base, (bar) - 2) -static const struct intel_ntb_reg bwd_reg; -static const struct intel_ntb_alt_reg bwd_pri_reg; -static const struct intel_ntb_alt_reg bwd_sec_reg; -static const struct intel_ntb_alt_reg bwd_b2b_reg; -static const struct intel_ntb_xlat_reg bwd_pri_xlat; -static const struct intel_ntb_xlat_reg bwd_sec_xlat; -static const struct intel_ntb_reg snb_reg; -static const struct intel_ntb_alt_reg snb_pri_reg; -static const struct intel_ntb_alt_reg snb_sec_reg; -static const struct intel_ntb_alt_reg snb_b2b_reg; -static const struct intel_ntb_xlat_reg snb_pri_xlat; -static const struct intel_ntb_xlat_reg snb_sec_xlat; -static struct intel_b2b_addr snb_b2b_usd_addr; -static struct intel_b2b_addr snb_b2b_dsd_addr; +static const struct intel_ntb_reg atom_reg; +static const struct intel_ntb_alt_reg atom_pri_reg; +static const struct intel_ntb_alt_reg atom_sec_reg; +static const struct intel_ntb_alt_reg atom_b2b_reg; +static const struct intel_ntb_xlat_reg atom_pri_xlat; +static const struct intel_ntb_xlat_reg atom_sec_xlat; +static const struct intel_ntb_reg xeon_reg; +static const struct intel_ntb_alt_reg xeon_pri_reg; +static const struct intel_ntb_alt_reg xeon_sec_reg; +static const struct intel_ntb_alt_reg xeon_b2b_reg; +static const struct intel_ntb_xlat_reg xeon_pri_xlat; +static const struct intel_ntb_xlat_reg xeon_sec_xlat; +static struct intel_b2b_addr xeon_b2b_usd_addr; +static struct intel_b2b_addr xeon_b2b_dsd_addr; static const struct ntb_dev_ops intel_ntb_ops; static const struct file_operations intel_ntb_debugfs_info; @@ -105,45 +105,45 @@ MODULE_PARM_DESC(b2b_mw_share, "If the b2b mw is large enough, configure the " "the mw, so the second half can still be used as a mw. Both " "sides MUST set the same value here!"); -module_param_named(snb_b2b_usd_bar2_addr64, - snb_b2b_usd_addr.bar2_addr64, ullong, 0644); -MODULE_PARM_DESC(snb_b2b_usd_bar2_addr64, - "SNB B2B USD BAR 2 64-bit address"); - -module_param_named(snb_b2b_usd_bar4_addr64, - snb_b2b_usd_addr.bar4_addr64, ullong, 0644); -MODULE_PARM_DESC(snb_b2b_usd_bar2_addr64, - "SNB B2B USD BAR 4 64-bit address"); - -module_param_named(snb_b2b_usd_bar4_addr32, - snb_b2b_usd_addr.bar4_addr32, ullong, 0644); -MODULE_PARM_DESC(snb_b2b_usd_bar2_addr64, - "SNB B2B USD split-BAR 4 32-bit address"); - -module_param_named(snb_b2b_usd_bar5_addr32, - snb_b2b_usd_addr.bar5_addr32, ullong, 0644); -MODULE_PARM_DESC(snb_b2b_usd_bar2_addr64, - "SNB B2B USD split-BAR 5 32-bit address"); - -module_param_named(snb_b2b_dsd_bar2_addr64, - snb_b2b_dsd_addr.bar2_addr64, ullong, 0644); -MODULE_PARM_DESC(snb_b2b_dsd_bar2_addr64, - "SNB B2B DSD BAR 2 64-bit address"); - -module_param_named(snb_b2b_dsd_bar4_addr64, - snb_b2b_dsd_addr.bar4_addr64, ullong, 0644); -MODULE_PARM_DESC(snb_b2b_dsd_bar2_addr64, - "SNB B2B DSD BAR 4 64-bit address"); - -module_param_named(snb_b2b_dsd_bar4_addr32, - snb_b2b_dsd_addr.bar4_addr32, ullong, 0644); -MODULE_PARM_DESC(snb_b2b_dsd_bar2_addr64, - "SNB B2B DSD split-BAR 4 32-bit address"); - -module_param_named(snb_b2b_dsd_bar5_addr32, - snb_b2b_dsd_addr.bar5_addr32, ullong, 0644); -MODULE_PARM_DESC(snb_b2b_dsd_bar2_addr64, - "SNB B2B DSD split-BAR 5 32-bit address"); +module_param_named(xeon_b2b_usd_bar2_addr64, + xeon_b2b_usd_addr.bar2_addr64, ullong, 0644); +MODULE_PARM_DESC(xeon_b2b_usd_bar2_addr64, + "XEON B2B USD BAR 2 64-bit address"); + +module_param_named(xeon_b2b_usd_bar4_addr64, + xeon_b2b_usd_addr.bar4_addr64, ullong, 0644); +MODULE_PARM_DESC(xeon_b2b_usd_bar2_addr64, + "XEON B2B USD BAR 4 64-bit address"); + +module_param_named(xeon_b2b_usd_bar4_addr32, + xeon_b2b_usd_addr.bar4_addr32, ullong, 0644); +MODULE_PARM_DESC(xeon_b2b_usd_bar2_addr64, + "XEON B2B USD split-BAR 4 32-bit address"); + +module_param_named(xeon_b2b_usd_bar5_addr32, + xeon_b2b_usd_addr.bar5_addr32, ullong, 0644); +MODULE_PARM_DESC(xeon_b2b_usd_bar2_addr64, + "XEON B2B USD split-BAR 5 32-bit address"); + +module_param_named(xeon_b2b_dsd_bar2_addr64, + xeon_b2b_dsd_addr.bar2_addr64, ullong, 0644); +MODULE_PARM_DESC(xeon_b2b_dsd_bar2_addr64, + "XEON B2B DSD BAR 2 64-bit address"); + +module_param_named(xeon_b2b_dsd_bar4_addr64, + xeon_b2b_dsd_addr.bar4_addr64, ullong, 0644); +MODULE_PARM_DESC(xeon_b2b_dsd_bar2_addr64, + "XEON B2B DSD BAR 4 64-bit address"); + +module_param_named(xeon_b2b_dsd_bar4_addr32, + xeon_b2b_dsd_addr.bar4_addr32, ullong, 0644); +MODULE_PARM_DESC(xeon_b2b_dsd_bar2_addr64, + "XEON B2B DSD split-BAR 4 32-bit address"); + +module_param_named(xeon_b2b_dsd_bar5_addr32, + xeon_b2b_dsd_addr.bar5_addr32, ullong, 0644); +MODULE_PARM_DESC(xeon_b2b_dsd_bar2_addr64, + "XEON B2B DSD split-BAR 5 32-bit address"); #ifndef ioread64 #ifdef readq @@ -174,7 +174,7 @@ static inline void _iowrite64(u64 val, void __iomem *mmio) #endif #endif -static inline int pdev_is_bwd(struct pci_dev *pdev) +static inline int pdev_is_atom(struct pci_dev *pdev) { switch (pdev->device) { case PCI_DEVICE_ID_INTEL_NTB_B2B_BWD: @@ -183,7 +183,7 @@ static inline int pdev_is_bwd(struct pci_dev *pdev) return 0; } -static inline int pdev_is_snb(struct pci_dev *pdev) +static inline int pdev_is_xeon(struct pci_dev *pdev) { switch (pdev->device) { case PCI_DEVICE_ID_INTEL_NTB_SS_JSF: @@ -636,70 +636,70 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf, off += scnprintf(buf + off, buf_size - off, "LMT45 -\t\t\t%#018llx\n", u.v64); - if (pdev_is_snb(ndev->ntb.pdev)) { + if (pdev_is_xeon(ndev->ntb.pdev)) { if (ntb_topo_is_b2b(ndev->ntb.topo)) { off += scnprintf(buf + off, buf_size - off, "\nNTB Outgoing B2B XLAT:\n"); - u.v64 = ioread64(mmio + SNB_PBAR23XLAT_OFFSET); + u.v64 = ioread64(mmio + XEON_PBAR23XLAT_OFFSET); off += scnprintf(buf + off, buf_size - off, "B2B XLAT23 -\t\t%#018llx\n", u.v64); - u.v64 = ioread64(mmio + SNB_PBAR45XLAT_OFFSET); + u.v64 = ioread64(mmio + XEON_PBAR45XLAT_OFFSET); off += scnprintf(buf + off, buf_size - off, "B2B XLAT45 -\t\t%#018llx\n", u.v64); - u.v64 = ioread64(mmio + SNB_PBAR23LMT_OFFSET); + u.v64 = ioread64(mmio + XEON_PBAR23LMT_OFFSET); off += scnprintf(buf + off, buf_size - off, "B2B LMT23 -\t\t%#018llx\n", u.v64); - u.v64 = ioread64(mmio + SNB_PBAR45LMT_OFFSET); + u.v64 = ioread64(mmio + XEON_PBAR45LMT_OFFSET); off += scnprintf(buf + off, buf_size - off, "B2B LMT45 -\t\t%#018llx\n", u.v64); off += scnprintf(buf + off, buf_size - off, "\nNTB Secondary BAR:\n"); - u.v64 = ioread64(mmio + SNB_SBAR0BASE_OFFSET); + u.v64 = ioread64(mmio + XEON_SBAR0BASE_OFFSET); off += scnprintf(buf + off, buf_size - off, "SBAR01 -\t\t%#018llx\n", u.v64); - u.v64 = ioread64(mmio + SNB_SBAR23BASE_OFFSET); + u.v64 = ioread64(mmio + XEON_SBAR23BASE_OFFSET); off += scnprintf(buf + off, buf_size - off, "SBAR23 -\t\t%#018llx\n", u.v64); - u.v64 = ioread64(mmio + SNB_SBAR45BASE_OFFSET); + u.v64 = ioread64(mmio + XEON_SBAR45BASE_OFFSET); off += scnprintf(buf + off, buf_size - off, "SBAR45 -\t\t%#018llx\n", u.v64); } off += scnprintf(buf + off, buf_size - off, - "\nSNB NTB Statistics:\n"); + "\nXEON NTB Statistics:\n"); - u.v16 = ioread16(mmio + SNB_USMEMMISS_OFFSET); + u.v16 = ioread16(mmio + XEON_USMEMMISS_OFFSET); off += scnprintf(buf + off, buf_size - off, "Upstream Memory Miss -\t%u\n", u.v16); off += scnprintf(buf + off, buf_size - off, - "\nSNB NTB Hardware Errors:\n"); + "\nXEON NTB Hardware Errors:\n"); if (!pci_read_config_word(ndev->ntb.pdev, - SNB_DEVSTS_OFFSET, &u.v16)) + XEON_DEVSTS_OFFSET, &u.v16)) off += scnprintf(buf + off, buf_size - off, "DEVSTS -\t\t%#06x\n", u.v16); if (!pci_read_config_word(ndev->ntb.pdev, - SNB_LINK_STATUS_OFFSET, &u.v16)) + XEON_LINK_STATUS_OFFSET, &u.v16)) off += scnprintf(buf + off, buf_size - off, "LNKSTS -\t\t%#06x\n", u.v16); if (!pci_read_config_dword(ndev->ntb.pdev, - SNB_UNCERRSTS_OFFSET, &u.v32)) + XEON_UNCERRSTS_OFFSET, &u.v32)) off += scnprintf(buf + off, buf_size - off, "UNCERRSTS -\t\t%#06x\n", u.v32); if (!pci_read_config_dword(ndev->ntb.pdev, - SNB_CORERRSTS_OFFSET, &u.v32)) + XEON_CORERRSTS_OFFSET, &u.v32)) off += scnprintf(buf + off, buf_size - off, "CORERRSTS -\t\t%#06x\n", u.v32); } @@ -1091,67 +1091,67 @@ static int intel_ntb_peer_spad_write(struct ntb_dev *ntb, ndev->peer_reg->spad); } -/* BWD */ +/* ATOM */ -static u64 bwd_db_ioread(void __iomem *mmio) +static u64 atom_db_ioread(void __iomem *mmio) { return ioread64(mmio); } -static void bwd_db_iowrite(u64 bits, void __iomem *mmio) +static void atom_db_iowrite(u64 bits, void __iomem *mmio) { iowrite64(bits, mmio); } -static int bwd_poll_link(struct intel_ntb_dev *ndev) +static int atom_poll_link(struct intel_ntb_dev *ndev) { u32 ntb_ctl; - ntb_ctl = ioread32(ndev->self_mmio + BWD_NTBCNTL_OFFSET); + ntb_ctl = ioread32(ndev->self_mmio + ATOM_NTBCNTL_OFFSET); if (ntb_ctl == ndev->ntb_ctl) return 0; ndev->ntb_ctl = ntb_ctl; - ndev->lnk_sta = ioread32(ndev->self_mmio + BWD_LINK_STATUS_OFFSET); + ndev->lnk_sta = ioread32(ndev->self_mmio + ATOM_LINK_STATUS_OFFSET); return 1; } -static int bwd_link_is_up(struct intel_ntb_dev *ndev) +static int atom_link_is_up(struct intel_ntb_dev *ndev) { - return BWD_NTB_CTL_ACTIVE(ndev->ntb_ctl); + return ATOM_NTB_CTL_ACTIVE(ndev->ntb_ctl); } -static int bwd_link_is_err(struct intel_ntb_dev *ndev) +static int atom_link_is_err(struct intel_ntb_dev *ndev) { - if (ioread32(ndev->self_mmio + BWD_LTSSMSTATEJMP_OFFSET) - & BWD_LTSSMSTATEJMP_FORCEDETECT) + if (ioread32(ndev->self_mmio + ATOM_LTSSMSTATEJMP_OFFSET) + & ATOM_LTSSMSTATEJMP_FORCEDETECT) return 1; - if (ioread32(ndev->self_mmio + BWD_IBSTERRRCRVSTS0_OFFSET) - & BWD_IBIST_ERR_OFLOW) + if (ioread32(ndev->self_mmio + ATOM_IBSTERRRCRVSTS0_OFFSET) + & ATOM_IBIST_ERR_OFLOW) return 1; return 0; } -static inline enum ntb_topo bwd_ppd_topo(struct intel_ntb_dev *ndev, u32 ppd) +static inline enum ntb_topo atom_ppd_topo(struct intel_ntb_dev *ndev, u32 ppd) { - switch (ppd & BWD_PPD_TOPO_MASK) { - case BWD_PPD_TOPO_B2B_USD: + switch (ppd & ATOM_PPD_TOPO_MASK) { + case ATOM_PPD_TOPO_B2B_USD: dev_dbg(ndev_dev(ndev), "PPD %d B2B USD\n", ppd); return NTB_TOPO_B2B_USD; - case BWD_PPD_TOPO_B2B_DSD: + case ATOM_PPD_TOPO_B2B_DSD: dev_dbg(ndev_dev(ndev), "PPD %d B2B DSD\n", ppd); return NTB_TOPO_B2B_DSD; - case BWD_PPD_TOPO_PRI_USD: - case BWD_PPD_TOPO_PRI_DSD: /* accept bogus PRI_DSD */ - case BWD_PPD_TOPO_SEC_USD: - case BWD_PPD_TOPO_SEC_DSD: /* accept bogus SEC_DSD */ + case ATOM_PPD_TOPO_PRI_USD: + case ATOM_PPD_TOPO_PRI_DSD: /* accept bogus PRI_DSD */ + case ATOM_PPD_TOPO_SEC_USD: + case ATOM_PPD_TOPO_SEC_DSD: /* accept bogus SEC_DSD */ dev_dbg(ndev_dev(ndev), "PPD %d non B2B disabled\n", ppd); return NTB_TOPO_NONE; } @@ -1160,28 +1160,28 @@ static inline enum ntb_topo bwd_ppd_topo(struct intel_ntb_dev *ndev, u32 ppd) return NTB_TOPO_NONE; } -static void bwd_link_hb(struct work_struct *work) +static void atom_link_hb(struct work_struct *work) { struct intel_ntb_dev *ndev = hb_ndev(work); unsigned long poll_ts; void __iomem *mmio; u32 status32; - poll_ts = ndev->last_ts + BWD_LINK_HB_TIMEOUT; + poll_ts = ndev->last_ts + ATOM_LINK_HB_TIMEOUT; /* Delay polling the link status if an interrupt was received, * unless the cached link status says the link is down. */ - if (time_after(poll_ts, jiffies) && bwd_link_is_up(ndev)) { + if (time_after(poll_ts, jiffies) && atom_link_is_up(ndev)) { schedule_delayed_work(&ndev->hb_timer, poll_ts - jiffies); return; } - if (bwd_poll_link(ndev)) + if (atom_poll_link(ndev)) ntb_link_event(&ndev->ntb); - if (bwd_link_is_up(ndev) || !bwd_link_is_err(ndev)) { - schedule_delayed_work(&ndev->hb_timer, BWD_LINK_HB_TIMEOUT); + if (atom_link_is_up(ndev) || !atom_link_is_err(ndev)) { + schedule_delayed_work(&ndev->hb_timer, ATOM_LINK_HB_TIMEOUT); return; } @@ -1190,91 +1190,91 @@ static void bwd_link_hb(struct work_struct *work) mmio = ndev->self_mmio; /* Driver resets the NTB ModPhy lanes - magic! */ - iowrite8(0xe0, mmio + BWD_MODPHY_PCSREG6); - iowrite8(0x40, mmio + BWD_MODPHY_PCSREG4); - iowrite8(0x60, mmio + BWD_MODPHY_PCSREG4); - iowrite8(0x60, mmio + BWD_MODPHY_PCSREG6); + iowrite8(0xe0, mmio + ATOM_MODPHY_PCSREG6); + iowrite8(0x40, mmio + ATOM_MODPHY_PCSREG4); + iowrite8(0x60, mmio + ATOM_MODPHY_PCSREG4); + iowrite8(0x60, mmio + ATOM_MODPHY_PCSREG6); /* Driver waits 100ms to allow the NTB ModPhy to settle */ msleep(100); /* Clear AER Errors, write to clear */ - status32 = ioread32(mmio + BWD_ERRCORSTS_OFFSET); + status32 = ioread32(mmio + ATOM_ERRCORSTS_OFFSET); dev_dbg(ndev_dev(ndev), "ERRCORSTS = %x\n", status32); status32 &= PCI_ERR_COR_REP_ROLL; - iowrite32(status32, mmio + BWD_ERRCORSTS_OFFSET); + iowrite32(status32, mmio + ATOM_ERRCORSTS_OFFSET); /* Clear unexpected electrical idle event in LTSSM, write to clear */ - status32 = ioread32(mmio + BWD_LTSSMERRSTS0_OFFSET); + status32 = ioread32(mmio + ATOM_LTSSMERRSTS0_OFFSET); dev_dbg(ndev_dev(ndev), "LTSSMERRSTS0 = %x\n", status32); - status32 |= BWD_LTSSMERRSTS0_UNEXPECTEDEI; - iowrite32(status32, mmio + BWD_LTSSMERRSTS0_OFFSET); + status32 |= ATOM_LTSSMERRSTS0_UNEXPECTEDEI; + iowrite32(status32, mmio + ATOM_LTSSMERRSTS0_OFFSET); /* Clear DeSkew Buffer error, write to clear */ - status32 = ioread32(mmio + BWD_DESKEWSTS_OFFSET); + status32 = ioread32(mmio + ATOM_DESKEWSTS_OFFSET); dev_dbg(ndev_dev(ndev), "DESKEWSTS = %x\n", status32); - status32 |= BWD_DESKEWSTS_DBERR; - iowrite32(status32, mmio + BWD_DESKEWSTS_OFFSET); + status32 |= ATOM_DESKEWSTS_DBERR; + iowrite32(status32, mmio + ATOM_DESKEWSTS_OFFSET); - status32 = ioread32(mmio + BWD_IBSTERRRCRVSTS0_OFFSET); + status32 = ioread32(mmio + ATOM_IBSTERRRCRVSTS0_OFFSET); dev_dbg(ndev_dev(ndev), "IBSTERRRCRVSTS0 = %x\n", status32); - status32 &= BWD_IBIST_ERR_OFLOW; - iowrite32(status32, mmio + BWD_IBSTERRRCRVSTS0_OFFSET); + status32 &= ATOM_IBIST_ERR_OFLOW; + iowrite32(status32, mmio + ATOM_IBSTERRRCRVSTS0_OFFSET); /* Releases the NTB state machine to allow the link to retrain */ - status32 = ioread32(mmio + BWD_LTSSMSTATEJMP_OFFSET); + status32 = ioread32(mmio + ATOM_LTSSMSTATEJMP_OFFSET); dev_dbg(ndev_dev(ndev), "LTSSMSTATEJMP = %x\n", status32); - status32 &= ~BWD_LTSSMSTATEJMP_FORCEDETECT; - iowrite32(status32, mmio + BWD_LTSSMSTATEJMP_OFFSET); + status32 &= ~ATOM_LTSSMSTATEJMP_FORCEDETECT; + iowrite32(status32, mmio + ATOM_LTSSMSTATEJMP_OFFSET); /* There is a potential race between the 2 NTB devices recovering at the * same time. If the times are the same, the link will not recover and * the driver will be stuck in this loop forever. Add a random interval * to the recovery time to prevent this race. */ - schedule_delayed_work(&ndev->hb_timer, BWD_LINK_RECOVERY_TIME - + prandom_u32() % BWD_LINK_RECOVERY_TIME); + schedule_delayed_work(&ndev->hb_timer, ATOM_LINK_RECOVERY_TIME + + prandom_u32() % ATOM_LINK_RECOVERY_TIME); } -static int bwd_init_isr(struct intel_ntb_dev *ndev) +static int atom_init_isr(struct intel_ntb_dev *ndev) { int rc; - rc = ndev_init_isr(ndev, 1, BWD_DB_MSIX_VECTOR_COUNT, - BWD_DB_MSIX_VECTOR_SHIFT, BWD_DB_TOTAL_SHIFT); + rc = ndev_init_isr(ndev, 1, ATOM_DB_MSIX_VECTOR_COUNT, + ATOM_DB_MSIX_VECTOR_SHIFT, ATOM_DB_TOTAL_SHIFT); if (rc) return rc; - /* BWD doesn't have link status interrupt, poll on that platform */ + /* ATOM doesn't have link status interrupt, poll on that platform */ ndev->last_ts = jiffies; - INIT_DELAYED_WORK(&ndev->hb_timer, bwd_link_hb); - schedule_delayed_work(&ndev->hb_timer, BWD_LINK_HB_TIMEOUT); + INIT_DELAYED_WORK(&ndev->hb_timer, atom_link_hb); + schedule_delayed_work(&ndev->hb_timer, ATOM_LINK_HB_TIMEOUT); return 0; } -static void bwd_deinit_isr(struct intel_ntb_dev *ndev) +static void atom_deinit_isr(struct intel_ntb_dev *ndev) { cancel_delayed_work_sync(&ndev->hb_timer); ndev_deinit_isr(ndev); } -static int bwd_init_ntb(struct intel_ntb_dev *ndev) +static int atom_init_ntb(struct intel_ntb_dev *ndev) { - ndev->mw_count = BWD_MW_COUNT; - ndev->spad_count = BWD_SPAD_COUNT; - ndev->db_count = BWD_DB_COUNT; + ndev->mw_count = ATOM_MW_COUNT; + ndev->spad_count = ATOM_SPAD_COUNT; + ndev->db_count = ATOM_DB_COUNT; switch (ndev->ntb.topo) { case NTB_TOPO_B2B_USD: case NTB_TOPO_B2B_DSD: - ndev->self_reg = &bwd_pri_reg; - ndev->peer_reg = &bwd_b2b_reg; - ndev->xlat_reg = &bwd_sec_xlat; + ndev->self_reg = &atom_pri_reg; + ndev->peer_reg = &atom_b2b_reg; + ndev->xlat_reg = &atom_sec_xlat; /* Enable Bus Master and Memory Space on the secondary side */ iowrite16(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER, - ndev->self_mmio + BWD_SPCICMD_OFFSET); + ndev->self_mmio + ATOM_SPCICMD_OFFSET); break; @@ -1287,31 +1287,31 @@ static int bwd_init_ntb(struct intel_ntb_dev *ndev) return 0; } -static int bwd_init_dev(struct intel_ntb_dev *ndev) +static int atom_init_dev(struct intel_ntb_dev *ndev) { u32 ppd; int rc; - rc = pci_read_config_dword(ndev->ntb.pdev, BWD_PPD_OFFSET, &ppd); + rc = pci_read_config_dword(ndev->ntb.pdev, ATOM_PPD_OFFSET, &ppd); if (rc) return -EIO; - ndev->ntb.topo = bwd_ppd_topo(ndev, ppd); + ndev->ntb.topo = atom_ppd_topo(ndev, ppd); if (ndev->ntb.topo == NTB_TOPO_NONE) return -EINVAL; - rc = bwd_init_ntb(ndev); + rc = atom_init_ntb(ndev); if (rc) return rc; - rc = bwd_init_isr(ndev); + rc = atom_init_isr(ndev); if (rc) return rc; if (ndev->ntb.topo != NTB_TOPO_SEC) { /* Initiate PCI-E link training */ - rc = pci_write_config_dword(ndev->ntb.pdev, BWD_PPD_OFFSET, - ppd | BWD_PPD_INIT_LINK); + rc = pci_write_config_dword(ndev->ntb.pdev, ATOM_PPD_OFFSET, + ppd | ATOM_PPD_INIT_LINK); if (rc) return rc; } @@ -1319,24 +1319,24 @@ static int bwd_init_dev(struct intel_ntb_dev *ndev) return 0; } -static void bwd_deinit_dev(struct intel_ntb_dev *ndev) +static void atom_deinit_dev(struct intel_ntb_dev *ndev) { - bwd_deinit_isr(ndev); + atom_deinit_isr(ndev); } -/* SNB */ +/* XEON */ -static u64 snb_db_ioread(void __iomem *mmio) +static u64 xeon_db_ioread(void __iomem *mmio) { return (u64)ioread16(mmio); } -static void snb_db_iowrite(u64 bits, void __iomem *mmio) +static void xeon_db_iowrite(u64 bits, void __iomem *mmio) { iowrite16((u16)bits, mmio); } -static int snb_poll_link(struct intel_ntb_dev *ndev) +static int xeon_poll_link(struct intel_ntb_dev *ndev) { u16 reg_val; int rc; @@ -1346,7 +1346,7 @@ static int snb_poll_link(struct intel_ntb_dev *ndev) ndev->self_reg->db_bell); rc = pci_read_config_word(ndev->ntb.pdev, - SNB_LINK_STATUS_OFFSET, ®_val); + XEON_LINK_STATUS_OFFSET, ®_val); if (rc) return 0; @@ -1358,7 +1358,7 @@ static int snb_poll_link(struct intel_ntb_dev *ndev) return 1; } -static int snb_link_is_up(struct intel_ntb_dev *ndev) +static int xeon_link_is_up(struct intel_ntb_dev *ndev) { if (ndev->ntb.topo == NTB_TOPO_SEC) return 1; @@ -1366,52 +1366,52 @@ static int snb_link_is_up(struct intel_ntb_dev *ndev) return NTB_LNK_STA_ACTIVE(ndev->lnk_sta); } -static inline enum ntb_topo snb_ppd_topo(struct intel_ntb_dev *ndev, u8 ppd) +static inline enum ntb_topo xeon_ppd_topo(struct intel_ntb_dev *ndev, u8 ppd) { - switch (ppd & SNB_PPD_TOPO_MASK) { - case SNB_PPD_TOPO_B2B_USD: + switch (ppd & XEON_PPD_TOPO_MASK) { + case XEON_PPD_TOPO_B2B_USD: return NTB_TOPO_B2B_USD; - case SNB_PPD_TOPO_B2B_DSD: + case XEON_PPD_TOPO_B2B_DSD: return NTB_TOPO_B2B_DSD; - case SNB_PPD_TOPO_PRI_USD: - case SNB_PPD_TOPO_PRI_DSD: /* accept bogus PRI_DSD */ + case XEON_PPD_TOPO_PRI_USD: + case XEON_PPD_TOPO_PRI_DSD: /* accept bogus PRI_DSD */ return NTB_TOPO_PRI; - case SNB_PPD_TOPO_SEC_USD: - case SNB_PPD_TOPO_SEC_DSD: /* accept bogus SEC_DSD */ + case XEON_PPD_TOPO_SEC_USD: + case XEON_PPD_TOPO_SEC_DSD: /* accept bogus SEC_DSD */ return NTB_TOPO_SEC; } return NTB_TOPO_NONE; } -static inline int snb_ppd_bar4_split(struct intel_ntb_dev *ndev, u8 ppd) +static inline int xeon_ppd_bar4_split(struct intel_ntb_dev *ndev, u8 ppd) { - if (ppd & SNB_PPD_SPLIT_BAR_MASK) { + if (ppd & XEON_PPD_SPLIT_BAR_MASK) { dev_dbg(ndev_dev(ndev), "PPD %d split bar\n", ppd); return 1; } return 0; } -static int snb_init_isr(struct intel_ntb_dev *ndev) +static int xeon_init_isr(struct intel_ntb_dev *ndev) { - return ndev_init_isr(ndev, SNB_DB_MSIX_VECTOR_COUNT, - SNB_DB_MSIX_VECTOR_COUNT, - SNB_DB_MSIX_VECTOR_SHIFT, - SNB_DB_TOTAL_SHIFT); + return ndev_init_isr(ndev, XEON_DB_MSIX_VECTOR_COUNT, + XEON_DB_MSIX_VECTOR_COUNT, + XEON_DB_MSIX_VECTOR_SHIFT, + XEON_DB_TOTAL_SHIFT); } -static void snb_deinit_isr(struct intel_ntb_dev *ndev) +static void xeon_deinit_isr(struct intel_ntb_dev *ndev) { ndev_deinit_isr(ndev); } -static int snb_setup_b2b_mw(struct intel_ntb_dev *ndev, - const struct intel_b2b_addr *addr, - const struct intel_b2b_addr *peer_addr) +static int xeon_setup_b2b_mw(struct intel_ntb_dev *ndev, + const struct intel_b2b_addr *addr, + const struct intel_b2b_addr *peer_addr) { struct pci_dev *pdev; void __iomem *mmio; @@ -1438,11 +1438,11 @@ static int snb_setup_b2b_mw(struct intel_ntb_dev *ndev, dev_dbg(ndev_dev(ndev), "b2b bar size %#llx\n", bar_size); - if (b2b_mw_share && SNB_B2B_MIN_SIZE <= bar_size >> 1) { + if (b2b_mw_share && XEON_B2B_MIN_SIZE <= bar_size >> 1) { dev_dbg(ndev_dev(ndev), "b2b using first half of bar\n"); ndev->b2b_off = bar_size >> 1; - } else if (SNB_B2B_MIN_SIZE <= bar_size) { + } else if (XEON_B2B_MIN_SIZE <= bar_size) { dev_dbg(ndev_dev(ndev), "b2b using whole bar\n"); ndev->b2b_off = 0; @@ -1460,7 +1460,7 @@ static int snb_setup_b2b_mw(struct intel_ntb_dev *ndev, * Note: code for each specific bar size register, because the register * offsets are not in a consistent order (bar5sz comes after ppd, odd). */ - pci_read_config_byte(pdev, SNB_PBAR23SZ_OFFSET, &bar_sz); + pci_read_config_byte(pdev, XEON_PBAR23SZ_OFFSET, &bar_sz); dev_dbg(ndev_dev(ndev), "PBAR23SZ %#x\n", bar_sz); if (b2b_bar == 2) { if (ndev->b2b_off) @@ -1468,12 +1468,12 @@ static int snb_setup_b2b_mw(struct intel_ntb_dev *ndev, else bar_sz = 0; } - pci_write_config_byte(pdev, SNB_SBAR23SZ_OFFSET, bar_sz); - pci_read_config_byte(pdev, SNB_SBAR23SZ_OFFSET, &bar_sz); + pci_write_config_byte(pdev, XEON_SBAR23SZ_OFFSET, bar_sz); + pci_read_config_byte(pdev, XEON_SBAR23SZ_OFFSET, &bar_sz); dev_dbg(ndev_dev(ndev), "SBAR23SZ %#x\n", bar_sz); if (!ndev->bar4_split) { - pci_read_config_byte(pdev, SNB_PBAR45SZ_OFFSET, &bar_sz); + pci_read_config_byte(pdev, XEON_PBAR45SZ_OFFSET, &bar_sz); dev_dbg(ndev_dev(ndev), "PBAR45SZ %#x\n", bar_sz); if (b2b_bar == 4) { if (ndev->b2b_off) @@ -1481,11 +1481,11 @@ static int snb_setup_b2b_mw(struct intel_ntb_dev *ndev, else bar_sz = 0; } - pci_write_config_byte(pdev, SNB_SBAR45SZ_OFFSET, bar_sz); - pci_read_config_byte(pdev, SNB_SBAR45SZ_OFFSET, &bar_sz); + pci_write_config_byte(pdev, XEON_SBAR45SZ_OFFSET, bar_sz); + pci_read_config_byte(pdev, XEON_SBAR45SZ_OFFSET, &bar_sz); dev_dbg(ndev_dev(ndev), "SBAR45SZ %#x\n", bar_sz); } else { - pci_read_config_byte(pdev, SNB_PBAR4SZ_OFFSET, &bar_sz); + pci_read_config_byte(pdev, XEON_PBAR4SZ_OFFSET, &bar_sz); dev_dbg(ndev_dev(ndev), "PBAR4SZ %#x\n", bar_sz); if (b2b_bar == 4) { if (ndev->b2b_off) @@ -1493,11 +1493,11 @@ static int snb_setup_b2b_mw(struct intel_ntb_dev *ndev, else bar_sz = 0; } - pci_write_config_byte(pdev, SNB_SBAR4SZ_OFFSET, bar_sz); - pci_read_config_byte(pdev, SNB_SBAR4SZ_OFFSET, &bar_sz); + pci_write_config_byte(pdev, XEON_SBAR4SZ_OFFSET, bar_sz); + pci_read_config_byte(pdev, XEON_SBAR4SZ_OFFSET, &bar_sz); dev_dbg(ndev_dev(ndev), "SBAR4SZ %#x\n", bar_sz); - pci_read_config_byte(pdev, SNB_PBAR5SZ_OFFSET, &bar_sz); + pci_read_config_byte(pdev, XEON_PBAR5SZ_OFFSET, &bar_sz); dev_dbg(ndev_dev(ndev), "PBAR5SZ %#x\n", bar_sz); if (b2b_bar == 5) { if (ndev->b2b_off) @@ -1505,8 +1505,8 @@ static int snb_setup_b2b_mw(struct intel_ntb_dev *ndev, else bar_sz = 0; } - pci_write_config_byte(pdev, SNB_SBAR5SZ_OFFSET, bar_sz); - pci_read_config_byte(pdev, SNB_SBAR5SZ_OFFSET, &bar_sz); + pci_write_config_byte(pdev, XEON_SBAR5SZ_OFFSET, bar_sz); + pci_read_config_byte(pdev, XEON_SBAR5SZ_OFFSET, &bar_sz); dev_dbg(ndev_dev(ndev), "SBAR5SZ %#x\n", bar_sz); } @@ -1525,7 +1525,7 @@ static int snb_setup_b2b_mw(struct intel_ntb_dev *ndev, return -EIO; dev_dbg(ndev_dev(ndev), "SBAR01 %#018llx\n", bar_addr); - iowrite64(bar_addr, mmio + SNB_SBAR0BASE_OFFSET); + iowrite64(bar_addr, mmio + XEON_SBAR0BASE_OFFSET); /* Other SBAR are normally hit by the PBAR xlat, except for b2b bar. * The b2b bar is either disabled above, or configured half-size, and @@ -1533,96 +1533,96 @@ static int snb_setup_b2b_mw(struct intel_ntb_dev *ndev, */ bar_addr = addr->bar2_addr64 + (b2b_bar == 2 ? ndev->b2b_off : 0); - iowrite64(bar_addr, mmio + SNB_SBAR23BASE_OFFSET); - bar_addr = ioread64(mmio + SNB_SBAR23BASE_OFFSET); + iowrite64(bar_addr, mmio + XEON_SBAR23BASE_OFFSET); + bar_addr = ioread64(mmio + XEON_SBAR23BASE_OFFSET); dev_dbg(ndev_dev(ndev), "SBAR23 %#018llx\n", bar_addr); if (!ndev->bar4_split) { bar_addr = addr->bar4_addr64 + (b2b_bar == 4 ? ndev->b2b_off : 0); - iowrite64(bar_addr, mmio + SNB_SBAR45BASE_OFFSET); - bar_addr = ioread64(mmio + SNB_SBAR45BASE_OFFSET); + iowrite64(bar_addr, mmio + XEON_SBAR45BASE_OFFSET); + bar_addr = ioread64(mmio + XEON_SBAR45BASE_OFFSET); dev_dbg(ndev_dev(ndev), "SBAR45 %#018llx\n", bar_addr); } else { bar_addr = addr->bar4_addr32 + (b2b_bar == 4 ? ndev->b2b_off : 0); - iowrite32(bar_addr, mmio + SNB_SBAR4BASE_OFFSET); - bar_addr = ioread32(mmio + SNB_SBAR4BASE_OFFSET); + iowrite32(bar_addr, mmio + XEON_SBAR4BASE_OFFSET); + bar_addr = ioread32(mmio + XEON_SBAR4BASE_OFFSET); dev_dbg(ndev_dev(ndev), "SBAR4 %#010llx\n", bar_addr); bar_addr = addr->bar5_addr32 + (b2b_bar == 5 ? ndev->b2b_off : 0); - iowrite32(bar_addr, mmio + SNB_SBAR5BASE_OFFSET); - bar_addr = ioread32(mmio + SNB_SBAR5BASE_OFFSET); + iowrite32(bar_addr, mmio + XEON_SBAR5BASE_OFFSET); + bar_addr = ioread32(mmio + XEON_SBAR5BASE_OFFSET); dev_dbg(ndev_dev(ndev), "SBAR5 %#010llx\n", bar_addr); } /* setup incoming bar limits == base addrs (zero length windows) */ bar_addr = addr->bar2_addr64 + (b2b_bar == 2 ? ndev->b2b_off : 0); - iowrite64(bar_addr, mmio + SNB_SBAR23LMT_OFFSET); - bar_addr = ioread64(mmio + SNB_SBAR23LMT_OFFSET); + iowrite64(bar_addr, mmio + XEON_SBAR23LMT_OFFSET); + bar_addr = ioread64(mmio + XEON_SBAR23LMT_OFFSET); dev_dbg(ndev_dev(ndev), "SBAR23LMT %#018llx\n", bar_addr); if (!ndev->bar4_split) { bar_addr = addr->bar4_addr64 + (b2b_bar == 4 ? ndev->b2b_off : 0); - iowrite64(bar_addr, mmio + SNB_SBAR45LMT_OFFSET); - bar_addr = ioread64(mmio + SNB_SBAR45LMT_OFFSET); + iowrite64(bar_addr, mmio + XEON_SBAR45LMT_OFFSET); + bar_addr = ioread64(mmio + XEON_SBAR45LMT_OFFSET); dev_dbg(ndev_dev(ndev), "SBAR45LMT %#018llx\n", bar_addr); } else { bar_addr = addr->bar4_addr32 + (b2b_bar == 4 ? ndev->b2b_off : 0); - iowrite32(bar_addr, mmio + SNB_SBAR4LMT_OFFSET); - bar_addr = ioread32(mmio + SNB_SBAR4LMT_OFFSET); + iowrite32(bar_addr, mmio + XEON_SBAR4LMT_OFFSET); + bar_addr = ioread32(mmio + XEON_SBAR4LMT_OFFSET); dev_dbg(ndev_dev(ndev), "SBAR4LMT %#010llx\n", bar_addr); bar_addr = addr->bar5_addr32 + (b2b_bar == 5 ? ndev->b2b_off : 0); - iowrite32(bar_addr, mmio + SNB_SBAR5LMT_OFFSET); - bar_addr = ioread32(mmio + SNB_SBAR5LMT_OFFSET); + iowrite32(bar_addr, mmio + XEON_SBAR5LMT_OFFSET); + bar_addr = ioread32(mmio + XEON_SBAR5LMT_OFFSET); dev_dbg(ndev_dev(ndev), "SBAR5LMT %#05llx\n", bar_addr); } /* zero incoming translation addrs */ - iowrite64(0, mmio + SNB_SBAR23XLAT_OFFSET); + iowrite64(0, mmio + XEON_SBAR23XLAT_OFFSET); if (!ndev->bar4_split) { - iowrite64(0, mmio + SNB_SBAR45XLAT_OFFSET); + iowrite64(0, mmio + XEON_SBAR45XLAT_OFFSET); } else { - iowrite32(0, mmio + SNB_SBAR4XLAT_OFFSET); - iowrite32(0, mmio + SNB_SBAR5XLAT_OFFSET); + iowrite32(0, mmio + XEON_SBAR4XLAT_OFFSET); + iowrite32(0, mmio + XEON_SBAR5XLAT_OFFSET); } /* zero outgoing translation limits (whole bar size windows) */ - iowrite64(0, mmio + SNB_PBAR23LMT_OFFSET); + iowrite64(0, mmio + XEON_PBAR23LMT_OFFSET); if (!ndev->bar4_split) { - iowrite64(0, mmio + SNB_PBAR45LMT_OFFSET); + iowrite64(0, mmio + XEON_PBAR45LMT_OFFSET); } else { - iowrite32(0, mmio + SNB_PBAR4LMT_OFFSET); - iowrite32(0, mmio + SNB_PBAR5LMT_OFFSET); + iowrite32(0, mmio + XEON_PBAR4LMT_OFFSET); + iowrite32(0, mmio + XEON_PBAR5LMT_OFFSET); } /* set outgoing translation offsets */ bar_addr = peer_addr->bar2_addr64; - iowrite64(bar_addr, mmio + SNB_PBAR23XLAT_OFFSET); - bar_addr = ioread64(mmio + SNB_PBAR23XLAT_OFFSET); + iowrite64(bar_addr, mmio + XEON_PBAR23XLAT_OFFSET); + bar_addr = ioread64(mmio + XEON_PBAR23XLAT_OFFSET); dev_dbg(ndev_dev(ndev), "PBAR23XLAT %#018llx\n", bar_addr); if (!ndev->bar4_split) { bar_addr = peer_addr->bar4_addr64; - iowrite64(bar_addr, mmio + SNB_PBAR45XLAT_OFFSET); - bar_addr = ioread64(mmio + SNB_PBAR45XLAT_OFFSET); + iowrite64(bar_addr, mmio + XEON_PBAR45XLAT_OFFSET); + bar_addr = ioread64(mmio + XEON_PBAR45XLAT_OFFSET); dev_dbg(ndev_dev(ndev), "PBAR45XLAT %#018llx\n", bar_addr); } else { bar_addr = peer_addr->bar4_addr32; - iowrite32(bar_addr, mmio + SNB_PBAR4XLAT_OFFSET); - bar_addr = ioread32(mmio + SNB_PBAR4XLAT_OFFSET); + iowrite32(bar_addr, mmio + XEON_PBAR4XLAT_OFFSET); + bar_addr = ioread32(mmio + XEON_PBAR4XLAT_OFFSET); dev_dbg(ndev_dev(ndev), "PBAR4XLAT %#010llx\n", bar_addr); bar_addr = peer_addr->bar5_addr32; - iowrite32(bar_addr, mmio + SNB_PBAR5XLAT_OFFSET); - bar_addr = ioread32(mmio + SNB_PBAR5XLAT_OFFSET); + iowrite32(bar_addr, mmio + XEON_PBAR5XLAT_OFFSET); + bar_addr = ioread32(mmio + XEON_PBAR5XLAT_OFFSET); dev_dbg(ndev_dev(ndev), "PBAR5XLAT %#010llx\n", bar_addr); } @@ -1642,13 +1642,13 @@ static int snb_setup_b2b_mw(struct intel_ntb_dev *ndev, /* B2B_XLAT_OFFSET is 64bit, but can only take 32bit writes */ dev_dbg(ndev_dev(ndev), "B2BXLAT %#018llx\n", bar_addr); - iowrite32(bar_addr, mmio + SNB_B2B_XLAT_OFFSETL); - iowrite32(bar_addr >> 32, mmio + SNB_B2B_XLAT_OFFSETU); + iowrite32(bar_addr, mmio + XEON_B2B_XLAT_OFFSETL); + iowrite32(bar_addr >> 32, mmio + XEON_B2B_XLAT_OFFSETU); if (b2b_bar) { /* map peer ntb mmio config space registers */ ndev->peer_mmio = pci_iomap(pdev, b2b_bar, - SNB_B2B_MIN_SIZE); + XEON_B2B_MIN_SIZE); if (!ndev->peer_mmio) return -EIO; } @@ -1656,7 +1656,7 @@ static int snb_setup_b2b_mw(struct intel_ntb_dev *ndev, return 0; } -static int snb_init_ntb(struct intel_ntb_dev *ndev) +static int xeon_init_ntb(struct intel_ntb_dev *ndev) { int rc; u32 ntb_ctl; @@ -1664,11 +1664,11 @@ static int snb_init_ntb(struct intel_ntb_dev *ndev) if (ndev->bar4_split) ndev->mw_count = HSX_SPLIT_BAR_MW_COUNT; else - ndev->mw_count = SNB_MW_COUNT; + ndev->mw_count = XEON_MW_COUNT; - ndev->spad_count = SNB_SPAD_COUNT; - ndev->db_count = SNB_DB_COUNT; - ndev->db_link_mask = SNB_DB_LINK_BIT; + ndev->spad_count = XEON_SPAD_COUNT; + ndev->db_count = XEON_DB_COUNT; + ndev->db_link_mask = XEON_DB_LINK_BIT; switch (ndev->ntb.topo) { case NTB_TOPO_PRI: @@ -1684,9 +1684,9 @@ static int snb_init_ntb(struct intel_ntb_dev *ndev) /* use half the spads for the peer */ ndev->spad_count >>= 1; - ndev->self_reg = &snb_pri_reg; - ndev->peer_reg = &snb_sec_reg; - ndev->xlat_reg = &snb_sec_xlat; + ndev->self_reg = &xeon_pri_reg; + ndev->peer_reg = &xeon_sec_reg; + ndev->xlat_reg = &xeon_sec_xlat; break; case NTB_TOPO_SEC: @@ -1696,19 +1696,19 @@ static int snb_init_ntb(struct intel_ntb_dev *ndev) } /* use half the spads for the peer */ ndev->spad_count >>= 1; - ndev->self_reg = &snb_sec_reg; - ndev->peer_reg = &snb_pri_reg; - ndev->xlat_reg = &snb_pri_xlat; + ndev->self_reg = &xeon_sec_reg; + ndev->peer_reg = &xeon_pri_reg; + ndev->xlat_reg = &xeon_pri_xlat; break; case NTB_TOPO_B2B_USD: case NTB_TOPO_B2B_DSD: - ndev->self_reg = &snb_pri_reg; - ndev->peer_reg = &snb_b2b_reg; - ndev->xlat_reg = &snb_sec_xlat; + ndev->self_reg = &xeon_pri_reg; + ndev->peer_reg = &xeon_b2b_reg; + ndev->xlat_reg = &xeon_sec_xlat; if (ndev->hwerr_flags & NTB_HWERR_SDOORBELL_LOCKUP) { - ndev->peer_reg = &snb_pri_reg; + ndev->peer_reg = &xeon_pri_reg; if (b2b_mw_idx < 0) ndev->b2b_idx = b2b_mw_idx + ndev->mw_count; @@ -1725,20 +1725,20 @@ static int snb_init_ntb(struct intel_ntb_dev *ndev) } if (ndev->ntb.topo == NTB_TOPO_B2B_USD) { - rc = snb_setup_b2b_mw(ndev, - &snb_b2b_dsd_addr, - &snb_b2b_usd_addr); + rc = xeon_setup_b2b_mw(ndev, + &xeon_b2b_dsd_addr, + &xeon_b2b_usd_addr); } else { - rc = snb_setup_b2b_mw(ndev, - &snb_b2b_usd_addr, - &snb_b2b_dsd_addr); + rc = xeon_setup_b2b_mw(ndev, + &xeon_b2b_usd_addr, + &xeon_b2b_dsd_addr); } if (rc) return rc; /* Enable Bus Master and Memory Space on the secondary side */ iowrite16(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER, - ndev->self_mmio + SNB_SPCICMD_OFFSET); + ndev->self_mmio + XEON_SPCICMD_OFFSET); break; @@ -1755,7 +1755,7 @@ static int snb_init_ntb(struct intel_ntb_dev *ndev) return 0; } -static int snb_init_dev(struct intel_ntb_dev *ndev) +static int xeon_init_dev(struct intel_ntb_dev *ndev) { struct pci_dev *pdev; u8 ppd; @@ -1821,20 +1821,20 @@ static int snb_init_dev(struct intel_ntb_dev *ndev) break; } - ndev->reg = &snb_reg; + ndev->reg = &xeon_reg; - rc = pci_read_config_byte(pdev, SNB_PPD_OFFSET, &ppd); + rc = pci_read_config_byte(pdev, XEON_PPD_OFFSET, &ppd); if (rc) return -EIO; - ndev->ntb.topo = snb_ppd_topo(ndev, ppd); + ndev->ntb.topo = xeon_ppd_topo(ndev, ppd); dev_dbg(ndev_dev(ndev), "ppd %#x topo %s\n", ppd, ntb_topo_string(ndev->ntb.topo)); if (ndev->ntb.topo == NTB_TOPO_NONE) return -EINVAL; if (ndev->ntb.topo != NTB_TOPO_SEC) { - ndev->bar4_split = snb_ppd_bar4_split(ndev, ppd); + ndev->bar4_split = xeon_ppd_bar4_split(ndev, ppd); dev_dbg(ndev_dev(ndev), "ppd %#x bar4_split %d\n", ppd, ndev->bar4_split); } else { @@ -1849,16 +1849,16 @@ static int snb_init_dev(struct intel_ntb_dev *ndev) mem, ndev->bar4_split); } - rc = snb_init_ntb(ndev); + rc = xeon_init_ntb(ndev); if (rc) return rc; - return snb_init_isr(ndev); + return xeon_init_isr(ndev); } -static void snb_deinit_dev(struct intel_ntb_dev *ndev) +static void xeon_deinit_dev(struct intel_ntb_dev *ndev) { - snb_deinit_isr(ndev); + xeon_deinit_isr(ndev); } static int intel_ntb_init_pci(struct intel_ntb_dev *ndev, struct pci_dev *pdev) @@ -1963,7 +1963,7 @@ static int intel_ntb_pci_probe(struct pci_dev *pdev, node = dev_to_node(&pdev->dev); - if (pdev_is_bwd(pdev)) { + if (pdev_is_atom(pdev)) { ndev = kzalloc_node(sizeof(*ndev), GFP_KERNEL, node); if (!ndev) { rc = -ENOMEM; @@ -1976,11 +1976,11 @@ static int intel_ntb_pci_probe(struct pci_dev *pdev, if (rc) goto err_init_pci; - rc = bwd_init_dev(ndev); + rc = atom_init_dev(ndev); if (rc) goto err_init_dev; - } else if (pdev_is_snb(pdev)) { + } else if (pdev_is_xeon(pdev)) { ndev = kzalloc_node(sizeof(*ndev), GFP_KERNEL, node); if (!ndev) { rc = -ENOMEM; @@ -1993,7 +1993,7 @@ static int intel_ntb_pci_probe(struct pci_dev *pdev, if (rc) goto err_init_pci; - rc = snb_init_dev(ndev); + rc = xeon_init_dev(ndev); if (rc) goto err_init_dev; @@ -2016,10 +2016,10 @@ static int intel_ntb_pci_probe(struct pci_dev *pdev, err_register: ndev_deinit_debugfs(ndev); - if (pdev_is_bwd(pdev)) - bwd_deinit_dev(ndev); - else if (pdev_is_snb(pdev)) - snb_deinit_dev(ndev); + if (pdev_is_atom(pdev)) + atom_deinit_dev(ndev); + else if (pdev_is_xeon(pdev)) + xeon_deinit_dev(ndev); err_init_dev: intel_ntb_deinit_pci(ndev); err_init_pci: @@ -2034,70 +2034,70 @@ static void intel_ntb_pci_remove(struct pci_dev *pdev) ntb_unregister_device(&ndev->ntb); ndev_deinit_debugfs(ndev); - if (pdev_is_bwd(pdev)) - bwd_deinit_dev(ndev); - else if (pdev_is_snb(pdev)) - snb_deinit_dev(ndev); + if (pdev_is_atom(pdev)) + atom_deinit_dev(ndev); + else if (pdev_is_xeon(pdev)) + xeon_deinit_dev(ndev); intel_ntb_deinit_pci(ndev); kfree(ndev); } -static const struct intel_ntb_reg bwd_reg = { - .poll_link = bwd_poll_link, - .link_is_up = bwd_link_is_up, - .db_ioread = bwd_db_ioread, - .db_iowrite = bwd_db_iowrite, +static const struct intel_ntb_reg atom_reg = { + .poll_link = atom_poll_link, + .link_is_up = atom_link_is_up, + .db_ioread = atom_db_ioread, + .db_iowrite = atom_db_iowrite, .db_size = sizeof(u64), - .ntb_ctl = BWD_NTBCNTL_OFFSET, + .ntb_ctl = ATOM_NTBCNTL_OFFSET, .mw_bar = {2, 4}, }; -static const struct intel_ntb_alt_reg bwd_pri_reg = { - .db_bell = BWD_PDOORBELL_OFFSET, - .db_mask = BWD_PDBMSK_OFFSET, - .spad = BWD_SPAD_OFFSET, +static const struct intel_ntb_alt_reg atom_pri_reg = { + .db_bell = ATOM_PDOORBELL_OFFSET, + .db_mask = ATOM_PDBMSK_OFFSET, + .spad = ATOM_SPAD_OFFSET, }; -static const struct intel_ntb_alt_reg bwd_b2b_reg = { - .db_bell = BWD_B2B_DOORBELL_OFFSET, - .spad = BWD_B2B_SPAD_OFFSET, +static const struct intel_ntb_alt_reg atom_b2b_reg = { + .db_bell = ATOM_B2B_DOORBELL_OFFSET, + .spad = ATOM_B2B_SPAD_OFFSET, }; -static const struct intel_ntb_xlat_reg bwd_sec_xlat = { - /* FIXME : .bar0_base = BWD_SBAR0BASE_OFFSET, */ - /* FIXME : .bar2_limit = BWD_SBAR2LMT_OFFSET, */ - .bar2_xlat = BWD_SBAR2XLAT_OFFSET, +static const struct intel_ntb_xlat_reg atom_sec_xlat = { + /* FIXME : .bar0_base = ATOM_SBAR0BASE_OFFSET, */ + /* FIXME : .bar2_limit = ATOM_SBAR2LMT_OFFSET, */ + .bar2_xlat = ATOM_SBAR2XLAT_OFFSET, }; -static const struct intel_ntb_reg snb_reg = { - .poll_link = snb_poll_link, - .link_is_up = snb_link_is_up, - .db_ioread = snb_db_ioread, - .db_iowrite = snb_db_iowrite, +static const struct intel_ntb_reg xeon_reg = { + .poll_link = xeon_poll_link, + .link_is_up = xeon_link_is_up, + .db_ioread = xeon_db_ioread, + .db_iowrite = xeon_db_iowrite, .db_size = sizeof(u32), - .ntb_ctl = SNB_NTBCNTL_OFFSET, + .ntb_ctl = XEON_NTBCNTL_OFFSET, .mw_bar = {2, 4, 5}, }; -static const struct intel_ntb_alt_reg snb_pri_reg = { - .db_bell = SNB_PDOORBELL_OFFSET, - .db_mask = SNB_PDBMSK_OFFSET, - .spad = SNB_SPAD_OFFSET, +static const struct intel_ntb_alt_reg xeon_pri_reg = { + .db_bell = XEON_PDOORBELL_OFFSET, + .db_mask = XEON_PDBMSK_OFFSET, + .spad = XEON_SPAD_OFFSET, }; -static const struct intel_ntb_alt_reg snb_sec_reg = { - .db_bell = SNB_SDOORBELL_OFFSET, - .db_mask = SNB_SDBMSK_OFFSET, +static const struct intel_ntb_alt_reg xeon_sec_reg = { + .db_bell = XEON_SDOORBELL_OFFSET, + .db_mask = XEON_SDBMSK_OFFSET, /* second half of the scratchpads */ - .spad = SNB_SPAD_OFFSET + (SNB_SPAD_COUNT << 1), + .spad = XEON_SPAD_OFFSET + (XEON_SPAD_COUNT << 1), }; -static const struct intel_ntb_alt_reg snb_b2b_reg = { - .db_bell = SNB_B2B_DOORBELL_OFFSET, - .spad = SNB_B2B_SPAD_OFFSET, +static const struct intel_ntb_alt_reg xeon_b2b_reg = { + .db_bell = XEON_B2B_DOORBELL_OFFSET, + .spad = XEON_B2B_SPAD_OFFSET, }; -static const struct intel_ntb_xlat_reg snb_pri_xlat = { +static const struct intel_ntb_xlat_reg xeon_pri_xlat = { /* Note: no primary .bar0_base visible to the secondary side. * * The secondary side cannot get the base address stored in primary @@ -2108,28 +2108,28 @@ static const struct intel_ntb_xlat_reg snb_pri_xlat = { * window by setting the limit equal to base, nor can it limit the size * of the memory window by setting the limit to base + size. */ - .bar2_limit = SNB_PBAR23LMT_OFFSET, - .bar2_xlat = SNB_PBAR23XLAT_OFFSET, + .bar2_limit = XEON_PBAR23LMT_OFFSET, + .bar2_xlat = XEON_PBAR23XLAT_OFFSET, }; -static const struct intel_ntb_xlat_reg snb_sec_xlat = { - .bar0_base = SNB_SBAR0BASE_OFFSET, - .bar2_limit = SNB_SBAR23LMT_OFFSET, - .bar2_xlat = SNB_SBAR23XLAT_OFFSET, +static const struct intel_ntb_xlat_reg xeon_sec_xlat = { + .bar0_base = XEON_SBAR0BASE_OFFSET, + .bar2_limit = XEON_SBAR23LMT_OFFSET, + .bar2_xlat = XEON_SBAR23XLAT_OFFSET, }; -static struct intel_b2b_addr snb_b2b_usd_addr = { - .bar2_addr64 = SNB_B2B_BAR2_USD_ADDR64, - .bar4_addr64 = SNB_B2B_BAR4_USD_ADDR64, - .bar4_addr32 = SNB_B2B_BAR4_USD_ADDR32, - .bar5_addr32 = SNB_B2B_BAR5_USD_ADDR32, +static struct intel_b2b_addr xeon_b2b_usd_addr = { + .bar2_addr64 = XEON_B2B_BAR2_USD_ADDR64, + .bar4_addr64 = XEON_B2B_BAR4_USD_ADDR64, + .bar4_addr32 = XEON_B2B_BAR4_USD_ADDR32, + .bar5_addr32 = XEON_B2B_BAR5_USD_ADDR32, }; -static struct intel_b2b_addr snb_b2b_dsd_addr = { - .bar2_addr64 = SNB_B2B_BAR2_DSD_ADDR64, - .bar4_addr64 = SNB_B2B_BAR4_DSD_ADDR64, - .bar4_addr32 = SNB_B2B_BAR4_DSD_ADDR32, - .bar5_addr32 = SNB_B2B_BAR5_DSD_ADDR32, +static struct intel_b2b_addr xeon_b2b_dsd_addr = { + .bar2_addr64 = XEON_B2B_BAR2_DSD_ADDR64, + .bar4_addr64 = XEON_B2B_BAR4_DSD_ADDR64, + .bar4_addr32 = XEON_B2B_BAR4_DSD_ADDR32, + .bar5_addr32 = XEON_B2B_BAR5_DSD_ADDR32, }; /* operations for primary side of local ntb */ diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.h b/drivers/ntb/hw/intel/ntb_hw_intel.h index fec689dc95cf..7ddaf387b679 100644 --- a/drivers/ntb/hw/intel/ntb_hw_intel.h +++ b/drivers/ntb/hw/intel/ntb_hw_intel.h @@ -68,141 +68,141 @@ #define PCI_DEVICE_ID_INTEL_NTB_SS_HSX 0x2F0F #define PCI_DEVICE_ID_INTEL_NTB_B2B_BWD 0x0C4E -/* SNB hardware (and JSF, IVT, HSX) */ - -#define SNB_PBAR23LMT_OFFSET 0x0000 -#define SNB_PBAR45LMT_OFFSET 0x0008 -#define SNB_PBAR4LMT_OFFSET 0x0008 -#define SNB_PBAR5LMT_OFFSET 0x000c -#define SNB_PBAR23XLAT_OFFSET 0x0010 -#define SNB_PBAR45XLAT_OFFSET 0x0018 -#define SNB_PBAR4XLAT_OFFSET 0x0018 -#define SNB_PBAR5XLAT_OFFSET 0x001c -#define SNB_SBAR23LMT_OFFSET 0x0020 -#define SNB_SBAR45LMT_OFFSET 0x0028 -#define SNB_SBAR4LMT_OFFSET 0x0028 -#define SNB_SBAR5LMT_OFFSET 0x002c -#define SNB_SBAR23XLAT_OFFSET 0x0030 -#define SNB_SBAR45XLAT_OFFSET 0x0038 -#define SNB_SBAR4XLAT_OFFSET 0x0038 -#define SNB_SBAR5XLAT_OFFSET 0x003c -#define SNB_SBAR0BASE_OFFSET 0x0040 -#define SNB_SBAR23BASE_OFFSET 0x0048 -#define SNB_SBAR45BASE_OFFSET 0x0050 -#define SNB_SBAR4BASE_OFFSET 0x0050 -#define SNB_SBAR5BASE_OFFSET 0x0054 -#define SNB_SBDF_OFFSET 0x005c -#define SNB_NTBCNTL_OFFSET 0x0058 -#define SNB_PDOORBELL_OFFSET 0x0060 -#define SNB_PDBMSK_OFFSET 0x0062 -#define SNB_SDOORBELL_OFFSET 0x0064 -#define SNB_SDBMSK_OFFSET 0x0066 -#define SNB_USMEMMISS_OFFSET 0x0070 -#define SNB_SPAD_OFFSET 0x0080 -#define SNB_PBAR23SZ_OFFSET 0x00d0 -#define SNB_PBAR45SZ_OFFSET 0x00d1 -#define SNB_PBAR4SZ_OFFSET 0x00d1 -#define SNB_SBAR23SZ_OFFSET 0x00d2 -#define SNB_SBAR45SZ_OFFSET 0x00d3 -#define SNB_SBAR4SZ_OFFSET 0x00d3 -#define SNB_PPD_OFFSET 0x00d4 -#define SNB_PBAR5SZ_OFFSET 0x00d5 -#define SNB_SBAR5SZ_OFFSET 0x00d6 -#define SNB_WCCNTRL_OFFSET 0x00e0 -#define SNB_UNCERRSTS_OFFSET 0x014c -#define SNB_CORERRSTS_OFFSET 0x0158 -#define SNB_LINK_STATUS_OFFSET 0x01a2 -#define SNB_SPCICMD_OFFSET 0x0504 -#define SNB_DEVCTRL_OFFSET 0x0598 -#define SNB_DEVSTS_OFFSET 0x059a -#define SNB_SLINK_STATUS_OFFSET 0x05a2 -#define SNB_B2B_SPAD_OFFSET 0x0100 -#define SNB_B2B_DOORBELL_OFFSET 0x0140 -#define SNB_B2B_XLAT_OFFSETL 0x0144 -#define SNB_B2B_XLAT_OFFSETU 0x0148 -#define SNB_PPD_CONN_MASK 0x03 -#define SNB_PPD_CONN_TRANSPARENT 0x00 -#define SNB_PPD_CONN_B2B 0x01 -#define SNB_PPD_CONN_RP 0x02 -#define SNB_PPD_DEV_MASK 0x10 -#define SNB_PPD_DEV_USD 0x00 -#define SNB_PPD_DEV_DSD 0x10 -#define SNB_PPD_SPLIT_BAR_MASK 0x40 - -#define SNB_PPD_TOPO_MASK (SNB_PPD_CONN_MASK | SNB_PPD_DEV_MASK) -#define SNB_PPD_TOPO_PRI_USD (SNB_PPD_CONN_RP | SNB_PPD_DEV_USD) -#define SNB_PPD_TOPO_PRI_DSD (SNB_PPD_CONN_RP | SNB_PPD_DEV_DSD) -#define SNB_PPD_TOPO_SEC_USD (SNB_PPD_CONN_TRANSPARENT | SNB_PPD_DEV_USD) -#define SNB_PPD_TOPO_SEC_DSD (SNB_PPD_CONN_TRANSPARENT | SNB_PPD_DEV_DSD) -#define SNB_PPD_TOPO_B2B_USD (SNB_PPD_CONN_B2B | SNB_PPD_DEV_USD) -#define SNB_PPD_TOPO_B2B_DSD (SNB_PPD_CONN_B2B | SNB_PPD_DEV_DSD) - -#define SNB_MW_COUNT 2 +/* Intel Xeon hardware */ + +#define XEON_PBAR23LMT_OFFSET 0x0000 +#define XEON_PBAR45LMT_OFFSET 0x0008 +#define XEON_PBAR4LMT_OFFSET 0x0008 +#define XEON_PBAR5LMT_OFFSET 0x000c +#define XEON_PBAR23XLAT_OFFSET 0x0010 +#define XEON_PBAR45XLAT_OFFSET 0x0018 +#define XEON_PBAR4XLAT_OFFSET 0x0018 +#define XEON_PBAR5XLAT_OFFSET 0x001c +#define XEON_SBAR23LMT_OFFSET 0x0020 +#define XEON_SBAR45LMT_OFFSET 0x0028 +#define XEON_SBAR4LMT_OFFSET 0x0028 +#define XEON_SBAR5LMT_OFFSET 0x002c +#define XEON_SBAR23XLAT_OFFSET 0x0030 +#define XEON_SBAR45XLAT_OFFSET 0x0038 +#define XEON_SBAR4XLAT_OFFSET 0x0038 +#define XEON_SBAR5XLAT_OFFSET 0x003c +#define XEON_SBAR0BASE_OFFSET 0x0040 +#define XEON_SBAR23BASE_OFFSET 0x0048 +#define XEON_SBAR45BASE_OFFSET 0x0050 +#define XEON_SBAR4BASE_OFFSET 0x0050 +#define XEON_SBAR5BASE_OFFSET 0x0054 +#define XEON_SBDF_OFFSET 0x005c +#define XEON_NTBCNTL_OFFSET 0x0058 +#define XEON_PDOORBELL_OFFSET 0x0060 +#define XEON_PDBMSK_OFFSET 0x0062 +#define XEON_SDOORBELL_OFFSET 0x0064 +#define XEON_SDBMSK_OFFSET 0x0066 +#define XEON_USMEMMISS_OFFSET 0x0070 +#define XEON_SPAD_OFFSET 0x0080 +#define XEON_PBAR23SZ_OFFSET 0x00d0 +#define XEON_PBAR45SZ_OFFSET 0x00d1 +#define XEON_PBAR4SZ_OFFSET 0x00d1 +#define XEON_SBAR23SZ_OFFSET 0x00d2 +#define XEON_SBAR45SZ_OFFSET 0x00d3 +#define XEON_SBAR4SZ_OFFSET 0x00d3 +#define XEON_PPD_OFFSET 0x00d4 +#define XEON_PBAR5SZ_OFFSET 0x00d5 +#define XEON_SBAR5SZ_OFFSET 0x00d6 +#define XEON_WCCNTRL_OFFSET 0x00e0 +#define XEON_UNCERRSTS_OFFSET 0x014c +#define XEON_CORERRSTS_OFFSET 0x0158 +#define XEON_LINK_STATUS_OFFSET 0x01a2 +#define XEON_SPCICMD_OFFSET 0x0504 +#define XEON_DEVCTRL_OFFSET 0x0598 +#define XEON_DEVSTS_OFFSET 0x059a +#define XEON_SLINK_STATUS_OFFSET 0x05a2 +#define XEON_B2B_SPAD_OFFSET 0x0100 +#define XEON_B2B_DOORBELL_OFFSET 0x0140 +#define XEON_B2B_XLAT_OFFSETL 0x0144 +#define XEON_B2B_XLAT_OFFSETU 0x0148 +#define XEON_PPD_CONN_MASK 0x03 +#define XEON_PPD_CONN_TRANSPARENT 0x00 +#define XEON_PPD_CONN_B2B 0x01 +#define XEON_PPD_CONN_RP 0x02 +#define XEON_PPD_DEV_MASK 0x10 +#define XEON_PPD_DEV_USD 0x00 +#define XEON_PPD_DEV_DSD 0x10 +#define XEON_PPD_SPLIT_BAR_MASK 0x40 + +#define XEON_PPD_TOPO_MASK (XEON_PPD_CONN_MASK | XEON_PPD_DEV_MASK) +#define XEON_PPD_TOPO_PRI_USD (XEON_PPD_CONN_RP | XEON_PPD_DEV_USD) +#define XEON_PPD_TOPO_PRI_DSD (XEON_PPD_CONN_RP | XEON_PPD_DEV_DSD) +#define XEON_PPD_TOPO_SEC_USD (XEON_PPD_CONN_TRANSPARENT | XEON_PPD_DEV_USD) +#define XEON_PPD_TOPO_SEC_DSD (XEON_PPD_CONN_TRANSPARENT | XEON_PPD_DEV_DSD) +#define XEON_PPD_TOPO_B2B_USD (XEON_PPD_CONN_B2B | XEON_PPD_DEV_USD) +#define XEON_PPD_TOPO_B2B_DSD (XEON_PPD_CONN_B2B | XEON_PPD_DEV_DSD) + +#define XEON_MW_COUNT 2 #define HSX_SPLIT_BAR_MW_COUNT 3 -#define SNB_DB_COUNT 15 -#define SNB_DB_LINK 15 -#define SNB_DB_LINK_BIT BIT_ULL(SNB_DB_LINK) -#define SNB_DB_MSIX_VECTOR_COUNT 4 -#define SNB_DB_MSIX_VECTOR_SHIFT 5 -#define SNB_DB_TOTAL_SHIFT 16 -#define SNB_SPAD_COUNT 16 - -/* BWD hardware */ - -#define BWD_SBAR2XLAT_OFFSET 0x0008 -#define BWD_PDOORBELL_OFFSET 0x0020 -#define BWD_PDBMSK_OFFSET 0x0028 -#define BWD_NTBCNTL_OFFSET 0x0060 -#define BWD_SPAD_OFFSET 0x0080 -#define BWD_PPD_OFFSET 0x00d4 -#define BWD_PBAR2XLAT_OFFSET 0x8008 -#define BWD_B2B_DOORBELL_OFFSET 0x8020 -#define BWD_B2B_SPAD_OFFSET 0x8080 -#define BWD_SPCICMD_OFFSET 0xb004 -#define BWD_LINK_STATUS_OFFSET 0xb052 -#define BWD_ERRCORSTS_OFFSET 0xb110 -#define BWD_IP_BASE 0xc000 -#define BWD_DESKEWSTS_OFFSET (BWD_IP_BASE + 0x3024) -#define BWD_LTSSMERRSTS0_OFFSET (BWD_IP_BASE + 0x3180) -#define BWD_LTSSMSTATEJMP_OFFSET (BWD_IP_BASE + 0x3040) -#define BWD_IBSTERRRCRVSTS0_OFFSET (BWD_IP_BASE + 0x3324) -#define BWD_MODPHY_PCSREG4 0x1c004 -#define BWD_MODPHY_PCSREG6 0x1c006 - -#define BWD_PPD_INIT_LINK 0x0008 -#define BWD_PPD_CONN_MASK 0x0300 -#define BWD_PPD_CONN_TRANSPARENT 0x0000 -#define BWD_PPD_CONN_B2B 0x0100 -#define BWD_PPD_CONN_RP 0x0200 -#define BWD_PPD_DEV_MASK 0x1000 -#define BWD_PPD_DEV_USD 0x0000 -#define BWD_PPD_DEV_DSD 0x1000 -#define BWD_PPD_TOPO_MASK (BWD_PPD_CONN_MASK | BWD_PPD_DEV_MASK) -#define BWD_PPD_TOPO_PRI_USD (BWD_PPD_CONN_TRANSPARENT | BWD_PPD_DEV_USD) -#define BWD_PPD_TOPO_PRI_DSD (BWD_PPD_CONN_TRANSPARENT | BWD_PPD_DEV_DSD) -#define BWD_PPD_TOPO_SEC_USD (BWD_PPD_CONN_RP | BWD_PPD_DEV_USD) -#define BWD_PPD_TOPO_SEC_DSD (BWD_PPD_CONN_RP | BWD_PPD_DEV_DSD) -#define BWD_PPD_TOPO_B2B_USD (BWD_PPD_CONN_B2B | BWD_PPD_DEV_USD) -#define BWD_PPD_TOPO_B2B_DSD (BWD_PPD_CONN_B2B | BWD_PPD_DEV_DSD) - -#define BWD_MW_COUNT 2 -#define BWD_DB_COUNT 34 -#define BWD_DB_VALID_MASK (BIT_ULL(BWD_DB_COUNT) - 1) -#define BWD_DB_MSIX_VECTOR_COUNT 34 -#define BWD_DB_MSIX_VECTOR_SHIFT 1 -#define BWD_DB_TOTAL_SHIFT 34 -#define BWD_SPAD_COUNT 16 - -#define BWD_NTB_CTL_DOWN_BIT BIT(16) -#define BWD_NTB_CTL_ACTIVE(x) !(x & BWD_NTB_CTL_DOWN_BIT) - -#define BWD_DESKEWSTS_DBERR BIT(15) -#define BWD_LTSSMERRSTS0_UNEXPECTEDEI BIT(20) -#define BWD_LTSSMSTATEJMP_FORCEDETECT BIT(2) -#define BWD_IBIST_ERR_OFLOW 0x7FFF7FFF - -#define BWD_LINK_HB_TIMEOUT msecs_to_jiffies(1000) -#define BWD_LINK_RECOVERY_TIME msecs_to_jiffies(500) +#define XEON_DB_COUNT 15 +#define XEON_DB_LINK 15 +#define XEON_DB_LINK_BIT BIT_ULL(XEON_DB_LINK) +#define XEON_DB_MSIX_VECTOR_COUNT 4 +#define XEON_DB_MSIX_VECTOR_SHIFT 5 +#define XEON_DB_TOTAL_SHIFT 16 +#define XEON_SPAD_COUNT 16 + +/* Intel Atom hardware */ + +#define ATOM_SBAR2XLAT_OFFSET 0x0008 +#define ATOM_PDOORBELL_OFFSET 0x0020 +#define ATOM_PDBMSK_OFFSET 0x0028 +#define ATOM_NTBCNTL_OFFSET 0x0060 +#define ATOM_SPAD_OFFSET 0x0080 +#define ATOM_PPD_OFFSET 0x00d4 +#define ATOM_PBAR2XLAT_OFFSET 0x8008 +#define ATOM_B2B_DOORBELL_OFFSET 0x8020 +#define ATOM_B2B_SPAD_OFFSET 0x8080 +#define ATOM_SPCICMD_OFFSET 0xb004 +#define ATOM_LINK_STATUS_OFFSET 0xb052 +#define ATOM_ERRCORSTS_OFFSET 0xb110 +#define ATOM_IP_BASE 0xc000 +#define ATOM_DESKEWSTS_OFFSET (ATOM_IP_BASE + 0x3024) +#define ATOM_LTSSMERRSTS0_OFFSET (ATOM_IP_BASE + 0x3180) +#define ATOM_LTSSMSTATEJMP_OFFSET (ATOM_IP_BASE + 0x3040) +#define ATOM_IBSTERRRCRVSTS0_OFFSET (ATOM_IP_BASE + 0x3324) +#define ATOM_MODPHY_PCSREG4 0x1c004 +#define ATOM_MODPHY_PCSREG6 0x1c006 + +#define ATOM_PPD_INIT_LINK 0x0008 +#define ATOM_PPD_CONN_MASK 0x0300 +#define ATOM_PPD_CONN_TRANSPARENT 0x0000 +#define ATOM_PPD_CONN_B2B 0x0100 +#define ATOM_PPD_CONN_RP 0x0200 +#define ATOM_PPD_DEV_MASK 0x1000 +#define ATOM_PPD_DEV_USD 0x0000 +#define ATOM_PPD_DEV_DSD 0x1000 +#define ATOM_PPD_TOPO_MASK (ATOM_PPD_CONN_MASK | ATOM_PPD_DEV_MASK) +#define ATOM_PPD_TOPO_PRI_USD (ATOM_PPD_CONN_TRANSPARENT | ATOM_PPD_DEV_USD) +#define ATOM_PPD_TOPO_PRI_DSD (ATOM_PPD_CONN_TRANSPARENT | ATOM_PPD_DEV_DSD) +#define ATOM_PPD_TOPO_SEC_USD (ATOM_PPD_CONN_RP | ATOM_PPD_DEV_USD) +#define ATOM_PPD_TOPO_SEC_DSD (ATOM_PPD_CONN_RP | ATOM_PPD_DEV_DSD) +#define ATOM_PPD_TOPO_B2B_USD (ATOM_PPD_CONN_B2B | ATOM_PPD_DEV_USD) +#define ATOM_PPD_TOPO_B2B_DSD (ATOM_PPD_CONN_B2B | ATOM_PPD_DEV_DSD) + +#define ATOM_MW_COUNT 2 +#define ATOM_DB_COUNT 34 +#define ATOM_DB_VALID_MASK (BIT_ULL(ATOM_DB_COUNT) - 1) +#define ATOM_DB_MSIX_VECTOR_COUNT 34 +#define ATOM_DB_MSIX_VECTOR_SHIFT 1 +#define ATOM_DB_TOTAL_SHIFT 34 +#define ATOM_SPAD_COUNT 16 + +#define ATOM_NTB_CTL_DOWN_BIT BIT(16) +#define ATOM_NTB_CTL_ACTIVE(x) !(x & ATOM_NTB_CTL_DOWN_BIT) + +#define ATOM_DESKEWSTS_DBERR BIT(15) +#define ATOM_LTSSMERRSTS0_UNEXPECTEDEI BIT(20) +#define ATOM_LTSSMSTATEJMP_FORCEDETECT BIT(2) +#define ATOM_IBIST_ERR_OFLOW 0x7FFF7FFF + +#define ATOM_LINK_HB_TIMEOUT msecs_to_jiffies(1000) +#define ATOM_LINK_RECOVERY_TIME msecs_to_jiffies(500) /* Ntb control and link status */ @@ -224,19 +224,19 @@ /* Use the following addresses for translation between b2b ntb devices in case * the hardware default values are not reliable. */ -#define SNB_B2B_BAR0_USD_ADDR 0x1000000000000000ull -#define SNB_B2B_BAR2_USD_ADDR64 0x2000000000000000ull -#define SNB_B2B_BAR4_USD_ADDR64 0x4000000000000000ull -#define SNB_B2B_BAR4_USD_ADDR32 0x20000000u -#define SNB_B2B_BAR5_USD_ADDR32 0x40000000u -#define SNB_B2B_BAR0_DSD_ADDR 0x9000000000000000ull -#define SNB_B2B_BAR2_DSD_ADDR64 0xa000000000000000ull -#define SNB_B2B_BAR4_DSD_ADDR64 0xc000000000000000ull -#define SNB_B2B_BAR4_DSD_ADDR32 0xa0000000u -#define SNB_B2B_BAR5_DSD_ADDR32 0xc0000000u +#define XEON_B2B_BAR0_USD_ADDR 0x1000000000000000ull +#define XEON_B2B_BAR2_USD_ADDR64 0x2000000000000000ull +#define XEON_B2B_BAR4_USD_ADDR64 0x4000000000000000ull +#define XEON_B2B_BAR4_USD_ADDR32 0x20000000u +#define XEON_B2B_BAR5_USD_ADDR32 0x40000000u +#define XEON_B2B_BAR0_DSD_ADDR 0x9000000000000000ull +#define XEON_B2B_BAR2_DSD_ADDR64 0xa000000000000000ull +#define XEON_B2B_BAR4_DSD_ADDR64 0xc000000000000000ull +#define XEON_B2B_BAR4_DSD_ADDR32 0xa0000000u +#define XEON_B2B_BAR5_DSD_ADDR32 0xc0000000u /* The peer ntb secondary config space is 32KB fixed size */ -#define SNB_B2B_MIN_SIZE 0x8000 +#define XEON_B2B_MIN_SIZE 0x8000 /* flags to indicate hardware errata */ #define NTB_HWERR_SDOORBELL_LOCKUP BIT_ULL(0) -- cgit v1.2.3-70-g09d2 From 9891417de8a816de60faea8a2ff7a04c4b3cf3a1 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Wed, 3 Jun 2015 11:29:38 -0400 Subject: NTB: Increase transport MTU to 64k from 16k Benchmarking showed a significant performance increase with the MTU size to 64k instead of 16k. Change the driver default to 64k. Signed-off-by: Dave Jiang Signed-off-by: Jon Mason --- drivers/ntb/ntb_transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index e07b056af3be..1551493197b4 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c @@ -76,7 +76,7 @@ static unsigned long max_mw_size; module_param(max_mw_size, ulong, 0644); MODULE_PARM_DESC(max_mw_size, "Limit size of large memory windows"); -static unsigned int transport_mtu = 0x401E; +static unsigned int transport_mtu = 0x10000; module_param(transport_mtu, uint, 0644); MODULE_PARM_DESC(transport_mtu, "Maximum size of NTB transport packets"); -- cgit v1.2.3-70-g09d2 From 7eb387813db6730a5793cd53077b4039d948d17f Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Mon, 15 Jun 2015 08:21:33 -0400 Subject: NTB: Print driver name and version in module init Printouts driver name and version to indicate what is being loaded. Signed-off-by: Dave Jiang Signed-off-by: Jon Mason --- drivers/ntb/hw/intel/ntb_hw_intel.c | 4 ++++ drivers/ntb/ntb_transport.c | 2 ++ 2 files changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c index eeaa1e8f8bd8..70924e5c0c72 100644 --- a/drivers/ntb/hw/intel/ntb_hw_intel.c +++ b/drivers/ntb/hw/intel/ntb_hw_intel.c @@ -2012,6 +2012,8 @@ static int intel_ntb_pci_probe(struct pci_dev *pdev, if (rc) goto err_register; + dev_info(&pdev->dev, "NTB device registered.\n"); + return 0; err_register: @@ -2192,6 +2194,8 @@ static struct pci_driver intel_ntb_pci_driver = { static int __init intel_ntb_pci_driver_init(void) { + pr_info("%s %s\n", NTB_DESC, NTB_VER); + if (debugfs_initialized()) debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL); diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index 1551493197b4..efe3ad4122f2 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c @@ -1958,6 +1958,8 @@ static int __init ntb_transport_init(void) { int rc; + pr_info("%s, version %s\n", NTB_TRANSPORT_DESC, NTB_TRANSPORT_VER); + if (debugfs_initialized()) nt_debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL); -- cgit v1.2.3-70-g09d2 From fd839bf88485878ec602dbb3146fd44769eb3784 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Mon, 15 Jun 2015 08:22:30 -0400 Subject: NTB: Change WARN_ON_ONCE to pr_warn_once on unsafe The unsafe doorbell and scratchpad access should display reason when WARN is called. Otherwise we get a stack dump without any explanation. Signed-off-by: Dave Jiang Signed-off-by: Jon Mason --- drivers/ntb/hw/intel/ntb_hw_intel.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c index 70924e5c0c72..ba4dc0d7e1f3 100644 --- a/drivers/ntb/hw/intel/ntb_hw_intel.c +++ b/drivers/ntb/hw/intel/ntb_hw_intel.c @@ -246,7 +246,8 @@ static inline int ndev_db_addr(struct intel_ntb_dev *ndev, phys_addr_t *db_addr, resource_size_t *db_size, phys_addr_t reg_addr, unsigned long reg) { - WARN_ON_ONCE(ndev_is_unsafe(ndev, NTB_UNSAFE_DB)); + if (ndev_is_unsafe(ndev, NTB_UNSAFE_DB)) + pr_warn_once("%s: NTB unsafe doorbell access", __func__); if (db_addr) { *db_addr = reg_addr + reg; @@ -264,7 +265,8 @@ static inline int ndev_db_addr(struct intel_ntb_dev *ndev, static inline u64 ndev_db_read(struct intel_ntb_dev *ndev, void __iomem *mmio) { - WARN_ON_ONCE(ndev_is_unsafe(ndev, NTB_UNSAFE_DB)); + if (ndev_is_unsafe(ndev, NTB_UNSAFE_DB)) + pr_warn_once("%s: NTB unsafe doorbell access", __func__); return ndev->reg->db_ioread(mmio); } @@ -272,7 +274,8 @@ static inline u64 ndev_db_read(struct intel_ntb_dev *ndev, static inline int ndev_db_write(struct intel_ntb_dev *ndev, u64 db_bits, void __iomem *mmio) { - WARN_ON_ONCE(ndev_is_unsafe(ndev, NTB_UNSAFE_DB)); + if (ndev_is_unsafe(ndev, NTB_UNSAFE_DB)) + pr_warn_once("%s: NTB unsafe doorbell access", __func__); if (db_bits & ~ndev->db_valid_mask) return -EINVAL; @@ -287,7 +290,8 @@ static inline int ndev_db_set_mask(struct intel_ntb_dev *ndev, u64 db_bits, { unsigned long irqflags; - WARN_ON_ONCE(ndev_is_unsafe(ndev, NTB_UNSAFE_DB)); + if (ndev_is_unsafe(ndev, NTB_UNSAFE_DB)) + pr_warn_once("%s: NTB unsafe doorbell access", __func__); if (db_bits & ~ndev->db_valid_mask) return -EINVAL; @@ -307,7 +311,8 @@ static inline int ndev_db_clear_mask(struct intel_ntb_dev *ndev, u64 db_bits, { unsigned long irqflags; - WARN_ON_ONCE(ndev_is_unsafe(ndev, NTB_UNSAFE_DB)); + if (ndev_is_unsafe(ndev, NTB_UNSAFE_DB)) + pr_warn_once("%s: NTB unsafe doorbell access", __func__); if (db_bits & ~ndev->db_valid_mask) return -EINVAL; @@ -336,7 +341,8 @@ static inline int ndev_spad_addr(struct intel_ntb_dev *ndev, int idx, phys_addr_t *spad_addr, phys_addr_t reg_addr, unsigned long reg) { - WARN_ON_ONCE(ndev_is_unsafe(ndev, NTB_UNSAFE_SPAD)); + if (ndev_is_unsafe(ndev, NTB_UNSAFE_SPAD)) + pr_warn_once("%s: NTB unsafe scratchpad access", __func__); if (idx < 0 || idx >= ndev->spad_count) return -EINVAL; @@ -352,7 +358,8 @@ static inline int ndev_spad_addr(struct intel_ntb_dev *ndev, int idx, static inline u32 ndev_spad_read(struct intel_ntb_dev *ndev, int idx, void __iomem *mmio) { - WARN_ON_ONCE(ndev_is_unsafe(ndev, NTB_UNSAFE_SPAD)); + if (ndev_is_unsafe(ndev, NTB_UNSAFE_SPAD)) + pr_warn_once("%s: NTB unsafe scratchpad access", __func__); if (idx < 0 || idx >= ndev->spad_count) return 0; @@ -363,7 +370,8 @@ static inline u32 ndev_spad_read(struct intel_ntb_dev *ndev, int idx, static inline int ndev_spad_write(struct intel_ntb_dev *ndev, int idx, u32 val, void __iomem *mmio) { - WARN_ON_ONCE(ndev_is_unsafe(ndev, NTB_UNSAFE_SPAD)); + if (ndev_is_unsafe(ndev, NTB_UNSAFE_SPAD)) + pr_warn_once("%s: NTB unsafe scratchpad access", __func__); if (idx < 0 || idx >= ndev->spad_count) return -EINVAL; -- cgit v1.2.3-70-g09d2 From bf44fe4671f97ee17d178e08c2d3b346188d062b Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Thu, 18 Jun 2015 05:17:30 -0400 Subject: NTB: Add split BAR output for debugfs stats When split BAR is enabled, the driver needs to dump out the split BAR registers rather than the original 64bit BAR registers. Signed-off-by: Dave Jiang Signed-off-by: Jon Mason --- drivers/ntb/hw/intel/ntb_hw_intel.c | 83 ++++++++++++++++++++++++++++++------- 1 file changed, 68 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c index ba4dc0d7e1f3..87751cfd6f4f 100644 --- a/drivers/ntb/hw/intel/ntb_hw_intel.c +++ b/drivers/ntb/hw/intel/ntb_hw_intel.c @@ -632,17 +632,36 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf, off += scnprintf(buf + off, buf_size - off, "XLAT23 -\t\t%#018llx\n", u.v64); - u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_xlat, 4)); - off += scnprintf(buf + off, buf_size - off, - "XLAT45 -\t\t%#018llx\n", u.v64); + if (ndev->bar4_split) { + u.v32 = ioread32(mmio + bar2_off(ndev->xlat_reg->bar2_xlat, 4)); + off += scnprintf(buf + off, buf_size - off, + "XLAT4 -\t\t\t%#06x\n", u.v32); + + u.v32 = ioread32(mmio + bar2_off(ndev->xlat_reg->bar2_xlat, 5)); + off += scnprintf(buf + off, buf_size - off, + "XLAT5 -\t\t\t%#06x\n", u.v32); + } else { + u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_xlat, 4)); + off += scnprintf(buf + off, buf_size - off, + "XLAT45 -\t\t%#018llx\n", u.v64); + } u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_limit, 2)); off += scnprintf(buf + off, buf_size - off, "LMT23 -\t\t\t%#018llx\n", u.v64); - u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_limit, 4)); - off += scnprintf(buf + off, buf_size - off, - "LMT45 -\t\t\t%#018llx\n", u.v64); + if (ndev->bar4_split) { + u.v32 = ioread32(mmio + bar2_off(ndev->xlat_reg->bar2_limit, 4)); + off += scnprintf(buf + off, buf_size - off, + "LMT4 -\t\t\t%#06x\n", u.v32); + u.v32 = ioread32(mmio + bar2_off(ndev->xlat_reg->bar2_limit, 5)); + off += scnprintf(buf + off, buf_size - off, + "LMT5 -\t\t\t%#06x\n", u.v32); + } else { + u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_limit, 4)); + off += scnprintf(buf + off, buf_size - off, + "LMT45 -\t\t\t%#018llx\n", u.v64); + } if (pdev_is_xeon(ndev->ntb.pdev)) { if (ntb_topo_is_b2b(ndev->ntb.topo)) { @@ -653,17 +672,41 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf, off += scnprintf(buf + off, buf_size - off, "B2B XLAT23 -\t\t%#018llx\n", u.v64); - u.v64 = ioread64(mmio + XEON_PBAR45XLAT_OFFSET); - off += scnprintf(buf + off, buf_size - off, - "B2B XLAT45 -\t\t%#018llx\n", u.v64); + if (ndev->bar4_split) { + u.v32 = ioread32(mmio + XEON_PBAR4XLAT_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "B2B XLAT4 -\t\t%#06x\n", + u.v32); + u.v32 = ioread32(mmio + XEON_PBAR5XLAT_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "B2B XLAT5 -\t\t%#06x\n", + u.v32); + } else { + u.v64 = ioread64(mmio + XEON_PBAR45XLAT_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "B2B XLAT45 -\t\t%#018llx\n", + u.v64); + } u.v64 = ioread64(mmio + XEON_PBAR23LMT_OFFSET); off += scnprintf(buf + off, buf_size - off, "B2B LMT23 -\t\t%#018llx\n", u.v64); - u.v64 = ioread64(mmio + XEON_PBAR45LMT_OFFSET); - off += scnprintf(buf + off, buf_size - off, - "B2B LMT45 -\t\t%#018llx\n", u.v64); + if (ndev->bar4_split) { + u.v32 = ioread32(mmio + XEON_PBAR4LMT_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "B2B LMT4 -\t\t%#06x\n", + u.v32); + u.v32 = ioread32(mmio + XEON_PBAR5LMT_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "B2B LMT5 -\t\t%#06x\n", + u.v32); + } else { + u.v64 = ioread64(mmio + XEON_PBAR45LMT_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "B2B LMT45 -\t\t%#018llx\n", + u.v64); + } off += scnprintf(buf + off, buf_size - off, "\nNTB Secondary BAR:\n"); @@ -676,9 +719,19 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf, off += scnprintf(buf + off, buf_size - off, "SBAR23 -\t\t%#018llx\n", u.v64); - u.v64 = ioread64(mmio + XEON_SBAR45BASE_OFFSET); - off += scnprintf(buf + off, buf_size - off, - "SBAR45 -\t\t%#018llx\n", u.v64); + if (ndev->bar4_split) { + u.v32 = ioread32(mmio + XEON_SBAR4BASE_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "SBAR4 -\t\t\t%#06x\n", u.v32); + u.v32 = ioread32(mmio + XEON_SBAR5BASE_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "SBAR5 -\t\t\t%#06x\n", u.v32); + } else { + u.v64 = ioread64(mmio + XEON_SBAR45BASE_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "SBAR45 -\t\t%#018llx\n", + u.v64); + } } off += scnprintf(buf + off, buf_size - off, -- cgit v1.2.3-70-g09d2 From 159870d2413c92622790e9cecbce95099bed539a Mon Sep 17 00:00:00 2001 From: Vishnu Patekar Date: Sat, 30 May 2015 16:55:01 +0200 Subject: ARM: sunxi: Add Machine support for A33 Add machine support for the Allwinner A33 quad core cortex-a7 based SoC, which is similar to the A23 SoC. Signed-off-by: Vishnu Patekar Signed-off-by: Hans de Goede Signed-off-by: Maxime Ripard Tested-by: Chen-Yu Tsai --- Documentation/devicetree/bindings/arm/sunxi.txt | 1 + arch/arm/mach-sunxi/sunxi.c | 1 + drivers/clk/sunxi/clk-sunxi.c | 1 + 3 files changed, 3 insertions(+) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/arm/sunxi.txt b/Documentation/devicetree/bindings/arm/sunxi.txt index 3cb4b946ff2b..67da20539540 100644 --- a/Documentation/devicetree/bindings/arm/sunxi.txt +++ b/Documentation/devicetree/bindings/arm/sunxi.txt @@ -9,5 +9,6 @@ using one of the following compatible strings: allwinner,sun6i-a31 allwinner,sun7i-a20 allwinner,sun8i-a23 + allwinner,sun8i-a33 allwinner,sun8i-h3 allwinner,sun9i-a80 diff --git a/arch/arm/mach-sunxi/sunxi.c b/arch/arm/mach-sunxi/sunxi.c index 82709020c57c..65bab2876343 100644 --- a/arch/arm/mach-sunxi/sunxi.c +++ b/arch/arm/mach-sunxi/sunxi.c @@ -67,6 +67,7 @@ MACHINE_END static const char * const sun8i_board_dt_compat[] = { "allwinner,sun8i-a23", + "allwinner,sun8i-a33", "allwinner,sun8i-h3", NULL, }; diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c index 7e1e2bd189b6..6d25e4e9dfec 100644 --- a/drivers/clk/sunxi/clk-sunxi.c +++ b/drivers/clk/sunxi/clk-sunxi.c @@ -1389,6 +1389,7 @@ static void __init sun6i_init_clocks(struct device_node *node) CLK_OF_DECLARE(sun6i_a31_clk_init, "allwinner,sun6i-a31", sun6i_init_clocks); CLK_OF_DECLARE(sun6i_a31s_clk_init, "allwinner,sun6i-a31s", sun6i_init_clocks); CLK_OF_DECLARE(sun8i_a23_clk_init, "allwinner,sun8i-a23", sun6i_init_clocks); +CLK_OF_DECLARE(sun8i_a33_clk_init, "allwinner,sun8i-a33", sun6i_init_clocks); static void __init sun9i_init_clocks(struct device_node *node) { -- cgit v1.2.3-70-g09d2 From acb33cc541d7a5495b16a133702d4c401ea4e294 Mon Sep 17 00:00:00 2001 From: "Vutla, Lokesh" Date: Thu, 2 Jul 2015 18:33:28 +0530 Subject: crypto: omap-des - Fix unmapping of dma channels dma_unmap_sg() is being called twice after completing the task. Looks like this is a copy paste error when creating des driver. With this the following warn appears during boot: [ 4.210457] ------------[ cut here ]------------ [ 4.215114] WARNING: CPU: 0 PID: 0 at lib/dma-debug.c:1080 check_unmap+0x710/0x9a0() [ 4.222899] omap-des 480a5000.des: DMA-API: device driver tries to free DMA memory it has not allocated [device address=0x00000000ab2ce000] [size=8 bytes] [ 4.236785] Modules linked in: [ 4.239860] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 3.14.39-02999-g1bc045a-dirty #182 [ 4.247918] [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [ 4.255710] [] (show_stack) from [] (dump_stack+0x84/0xb8) [ 4.262977] [] (dump_stack) from [] (warn_slowpath_common+0x68/0x8c) [ 4.271107] [] (warn_slowpath_common) from [] (warn_slowpath_fmt+0x30/0x40) [ 4.279854] [] (warn_slowpath_fmt) from [] (check_unmap+0x710/0x9a0) [ 4.287991] [] (check_unmap) from [] (debug_dma_unmap_sg+0x90/0x19c) [ 4.296128] [] (debug_dma_unmap_sg) from [] (omap_des_done_task+0x1cc/0x3e4) [ 4.304963] [] (omap_des_done_task) from [] (tasklet_action+0x84/0x124) [ 4.313370] [] (tasklet_action) from [] (__do_softirq+0xf0/0x20c) [ 4.321235] [] (__do_softirq) from [] (irq_exit+0x98/0xec) [ 4.328500] [] (irq_exit) from [] (handle_IRQ+0x50/0xb0) [ 4.335589] [] (handle_IRQ) from [] (gic_handle_irq+0x28/0x5c) Removing the duplicate call to dma_unmap_sg(). Cc: stable@vger.kernel.org Reported-by: Tomi Valkeinen Signed-off-by: Lokesh Vutla Signed-off-by: Herbert Xu --- drivers/crypto/omap-des.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/omap-des.c b/drivers/crypto/omap-des.c index 46307098f8ba..0a70e46d5416 100644 --- a/drivers/crypto/omap-des.c +++ b/drivers/crypto/omap-des.c @@ -536,9 +536,6 @@ static int omap_des_crypt_dma_stop(struct omap_des_dev *dd) dmaengine_terminate_all(dd->dma_lch_in); dmaengine_terminate_all(dd->dma_lch_out); - dma_unmap_sg(dd->dev, dd->in_sg, dd->in_sg_len, DMA_TO_DEVICE); - dma_unmap_sg(dd->dev, dd->out_sg, dd->out_sg_len, DMA_FROM_DEVICE); - return err; } -- cgit v1.2.3-70-g09d2 From 0d7b6b1182ef6f72be592688c8a22025a5b7b483 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 2 Jul 2015 14:29:58 +0300 Subject: drm/i915/chv: fix HW readout of the port PLL fractional divider MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ville noticed that the PLL HW readout code parsed the fractional divider value as if the fractional divider was always enabled. This may result in a port clock state check mismatch if the preceeding modeset disabled the fractional divider, but left a non-zero divider value in the register. Signed-off-by: Imre Deak Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1b61f9810387..8aa803848f35 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7887,7 +7887,7 @@ static void chv_crtc_clock_get(struct intel_crtc *crtc, int pipe = pipe_config->cpu_transcoder; enum dpio_channel port = vlv_pipe_to_channel(pipe); intel_clock_t clock; - u32 cmn_dw13, pll_dw0, pll_dw1, pll_dw2; + u32 cmn_dw13, pll_dw0, pll_dw1, pll_dw2, pll_dw3; int refclk = 100000; mutex_lock(&dev_priv->sb_lock); @@ -7895,10 +7895,13 @@ static void chv_crtc_clock_get(struct intel_crtc *crtc, pll_dw0 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW0(port)); pll_dw1 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW1(port)); pll_dw2 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW2(port)); + pll_dw3 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW3(port)); mutex_unlock(&dev_priv->sb_lock); clock.m1 = (pll_dw1 & 0x7) == DPIO_CHV_M1_DIV_BY_2 ? 2 : 0; - clock.m2 = ((pll_dw0 & 0xff) << 22) | (pll_dw2 & 0x3fffff); + clock.m2 = (pll_dw0 & 0xff) << 22; + if (pll_dw3 & DPIO_CHV_FRAC_DIV_EN) + clock.m2 |= pll_dw2 & 0x3fffff; clock.n = (pll_dw1 >> DPIO_CHV_N_DIV_SHIFT) & 0xf; clock.p1 = (cmn_dw13 >> DPIO_CHV_P1_DIV_SHIFT) & 0x7; clock.p2 = (cmn_dw13 >> DPIO_CHV_P2_DIV_SHIFT) & 0x1f; -- cgit v1.2.3-70-g09d2 From 14f21189df33bc972455d6a0ed875aa68718d7fc Mon Sep 17 00:00:00 2001 From: Maninder Singh Date: Mon, 29 Jun 2015 16:05:11 +0530 Subject: cxl/vphb.c: Use phb pointer after NULL check static Anlaysis detected below error:- (error) Possible null pointer dereference: phb So, Use phb after NULL check. Signed-off-by: Maninder Singh Acked-by: Ian Munsie Signed-off-by: Michael Ellerman --- drivers/misc/cxl/vphb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/misc/cxl/vphb.c b/drivers/misc/cxl/vphb.c index b1d1983a84a5..2eba002b580b 100644 --- a/drivers/misc/cxl/vphb.c +++ b/drivers/misc/cxl/vphb.c @@ -112,9 +112,10 @@ static int cxl_pcie_config_info(struct pci_bus *bus, unsigned int devfn, unsigned long addr; phb = pci_bus_to_host(bus); - afu = (struct cxl_afu *)phb->private_data; if (phb == NULL) return PCIBIOS_DEVICE_NOT_FOUND; + afu = (struct cxl_afu *)phb->private_data; + if (cxl_pcie_cfg_record(bus->number, devfn) > afu->crs_num) return PCIBIOS_DEVICE_NOT_FOUND; if (offset >= (unsigned long)phb->cfg_data) -- cgit v1.2.3-70-g09d2 From 8c00d5c9d3e7452658dda55024485d52919ebfdd Mon Sep 17 00:00:00 2001 From: Daniel Axtens Date: Thu, 2 Jul 2015 15:55:21 +1000 Subject: cxl: Test the correct mmio space before unmapping Before freeing p2n, test p2n, not p1n. Signed-off-by: Daniel Axtens Acked-by: Ian Munsie Signed-off-by: Michael Ellerman --- drivers/misc/cxl/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c index c68ef5806dbe..32ad09705949 100644 --- a/drivers/misc/cxl/pci.c +++ b/drivers/misc/cxl/pci.c @@ -539,7 +539,7 @@ err: static void cxl_unmap_slice_regs(struct cxl_afu *afu) { - if (afu->p1n_mmio) + if (afu->p2n_mmio) iounmap(afu->p2n_mmio); if (afu->p1n_mmio) iounmap(afu->p1n_mmio); -- cgit v1.2.3-70-g09d2 From 6d451367bfa16fc103604bacd258f534c65d1540 Mon Sep 17 00:00:00 2001 From: Hai Li Date: Thu, 25 Jun 2015 18:35:33 -0400 Subject: clk: qcom: Use parent rate when set rate to pixel RCG clock Since the parent rate has been recalculated, pixel RCG clock should rely on it to find the correct M/N values during set_rate, instead of calling __clk_round_rate() to its parent again. Signed-off-by: Hai Li Tested-by: Archit Taneja Fixes: 99cbd064b059 ("clk: qcom: Support display RCG clocks") [sboyd@codeaurora.org: Silenced unused parent variable warning] Signed-off-by: Stephen Boyd --- drivers/clk/qcom/clk-rcg2.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index b95d17fbb8d7..92936f0912d2 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -530,19 +530,16 @@ static int clk_pixel_set_rate(struct clk_hw *hw, unsigned long rate, struct clk_rcg2 *rcg = to_clk_rcg2(hw); struct freq_tbl f = *rcg->freq_tbl; const struct frac_entry *frac = frac_table_pixel; - unsigned long request, src_rate; + unsigned long request; int delta = 100000; u32 mask = BIT(rcg->hid_width) - 1; u32 hid_div; - int index = qcom_find_src_index(hw, rcg->parent_map, f.src); - struct clk *parent = clk_get_parent_by_index(hw->clk, index); for (; frac->num; frac++) { request = (rate * frac->den) / frac->num; - src_rate = __clk_round_rate(parent, request); - if ((src_rate < (request - delta)) || - (src_rate > (request + delta))) + if ((parent_rate < (request - delta)) || + (parent_rate > (request + delta))) continue; regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, -- cgit v1.2.3-70-g09d2 From c14bada8f71eef63d4465aa8e3a479104a06e7c7 Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Tue, 23 Jun 2015 16:09:21 +0200 Subject: drivers: clk: st: Remove unused code Remove this duplicated code due to a bad copy / paste. Signed-off-by: Gabriel Fernandez Signed-off-by: Stephen Boyd --- drivers/clk/st/clkgen-fsyn.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/st/clkgen-fsyn.c b/drivers/clk/st/clkgen-fsyn.c index e94197f04b0b..099ed6050d25 100644 --- a/drivers/clk/st/clkgen-fsyn.c +++ b/drivers/clk/st/clkgen-fsyn.c @@ -1082,10 +1082,6 @@ static const struct of_device_id quadfs_of_match[] = { .compatible = "st,stih407-quadfs660-D", .data = &st_fs660c32_D_407 }, - { - .compatible = "st,stih407-quadfs660-D", - .data = (void *)&st_fs660c32_D_407 - }, {} }; -- cgit v1.2.3-70-g09d2 From c4d339c69f91c20def1366c1db8af6ac7a3013a9 Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Tue, 23 Jun 2015 16:09:22 +0200 Subject: drivers: clk: st: Fix FSYN channel values This patch fixes the value for disabling the FSYN channel clock. The 'is_enabled' returned value is also fixed. Signed-off-by: Pankaj Dev Signed-off-by: Gabriel Fernandez Signed-off-by: Stephen Boyd --- drivers/clk/st/clkgen-fsyn.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/st/clkgen-fsyn.c b/drivers/clk/st/clkgen-fsyn.c index 099ed6050d25..95851c464478 100644 --- a/drivers/clk/st/clkgen-fsyn.c +++ b/drivers/clk/st/clkgen-fsyn.c @@ -489,7 +489,7 @@ static int quadfs_pll_is_enabled(struct clk_hw *hw) struct st_clk_quadfs_pll *pll = to_quadfs_pll(hw); u32 npda = CLKGEN_READ(pll, npda); - return !!npda; + return pll->data->powerup_polarity ? !npda : !!npda; } static int clk_fs660c32_vco_get_rate(unsigned long input, struct stm_fs *fs, @@ -774,7 +774,7 @@ static void quadfs_fsynth_disable(struct clk_hw *hw) if (fs->lock) spin_lock_irqsave(fs->lock, flags); - CLKGEN_WRITE(fs, nsb[fs->chan], !fs->data->standby_polarity); + CLKGEN_WRITE(fs, nsb[fs->chan], fs->data->standby_polarity); if (fs->lock) spin_unlock_irqrestore(fs->lock, flags); -- cgit v1.2.3-70-g09d2 From 0f4f2afd4402883a51ad27a1d9e046643bb1e3cb Mon Sep 17 00:00:00 2001 From: Giuseppe Cavallaro Date: Tue, 23 Jun 2015 16:09:23 +0200 Subject: drivers: clk: st: Fix flexgen lock init While proving lock, the following warning happens and it is fixed after initializing lock in the setup function INFO: trying to register non-static key. the code is fine but needs lockdep annotation. turning off the locking correctness validator. CPU: 0 PID: 0 Comm: swapper/0 Not tainted 3.10.27-02861-g39df285-dirty #33 [] (unwind_backtrace+0x0/0xf4) from [] (show_stack+0x10/0x14) [] (show_stack+0x10/0x14) from [] (__lock_acquire+0x900/0xb14) [] (__lock_acquire+0x900/0xb14) from [] (lock_acquire+0x68/0x7c) [] (lock_acquire+0x68/0x7c) from [] (_raw_spin_lock_irqsave+0x48/0x5c) [] (_raw_spin_lock_irqsave+0x48/0x5c) from [] (clk_gate_endisable+0x28/0x88) [] (clk_gate_endisable+0x28/0x88) from [] (clk_gate_enable+0xc/0x14) [] (clk_gate_enable+0xc/0x14) from [] (flexgen_enable+0x28/0x40) [] (flexgen_enable+0x28/0x40) from [] (__clk_enable+0x5c/0x9c) [] (__clk_enable+0x5c/0x9c) from [] (clk_enable+0x18/0x2c) [] (clk_enable+0x18/0x2c) from [] (st_lpc_of_register+0xc0/0x248) [] (st_lpc_of_register+0xc0/0x248) from [] (clocksource_of_init+0x34/0x58) [] (clocksource_of_init+0x34/0x58) from [] (sti_timer_init+0x10/0x18) [] (sti_timer_init+0x10/0x18) from [] (time_init+0x20/0x30) [] (time_init+0x20/0x30) from [] (start_kernel+0x20c/0x2e8) [] (start_kernel+0x20c/0x2e8) from [<40008074>] (0x40008074) Signed-off-by: Giuseppe Cavallaro Signed-off-by: Gabriel Fernandez Fixes: b116517055b7 ("clk: st: STiH407: Support for Flexgen Clocks") Signed-off-by: Stephen Boyd --- drivers/clk/st/clk-flexgen.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/clk/st/clk-flexgen.c b/drivers/clk/st/clk-flexgen.c index 657ca14ba709..be06d2a79dce 100644 --- a/drivers/clk/st/clk-flexgen.c +++ b/drivers/clk/st/clk-flexgen.c @@ -303,6 +303,8 @@ static void __init st_of_flexgen_setup(struct device_node *np) if (!rlock) goto err; + spin_lock_init(rlock); + for (i = 0; i < clk_data->clk_num; i++) { struct clk *clk; const char *clk_name; -- cgit v1.2.3-70-g09d2 From 18fee4538fe534c53fa95fe9eaa7f96586814e0a Mon Sep 17 00:00:00 2001 From: Pankaj Dev Date: Tue, 23 Jun 2015 16:09:24 +0200 Subject: drivers: clk: st: Add CLK_GET_RATE_NOCACHE flag to clocks Add the CLK_GET_RATE_NOCACHE flag to all the clocks with recalc ops, so that they reflect Hw rate after CPS wake-up when a clk_get_rate() is called Signed-off-by: Pankaj Dev Signed-off-by: Gabriel Fernandez Signed-off-by: Stephen Boyd --- drivers/clk/st/clk-flexgen.c | 2 +- drivers/clk/st/clkgen-fsyn.c | 2 +- drivers/clk/st/clkgen-mux.c | 8 +++++--- drivers/clk/st/clkgen-pll.c | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/st/clk-flexgen.c b/drivers/clk/st/clk-flexgen.c index be06d2a79dce..8dd8cce27361 100644 --- a/drivers/clk/st/clk-flexgen.c +++ b/drivers/clk/st/clk-flexgen.c @@ -190,7 +190,7 @@ static struct clk *clk_register_flexgen(const char *name, init.name = name; init.ops = &flexgen_ops; - init.flags = CLK_IS_BASIC | flexgen_flags; + init.flags = CLK_IS_BASIC | CLK_GET_RATE_NOCACHE | flexgen_flags; init.parent_names = parent_names; init.num_parents = num_parents; diff --git a/drivers/clk/st/clkgen-fsyn.c b/drivers/clk/st/clkgen-fsyn.c index 95851c464478..99c98c15d4a4 100644 --- a/drivers/clk/st/clkgen-fsyn.c +++ b/drivers/clk/st/clkgen-fsyn.c @@ -635,7 +635,7 @@ static struct clk * __init st_clk_register_quadfs_pll( init.name = name; init.ops = quadfs->pll_ops; - init.flags = CLK_IS_BASIC; + init.flags = CLK_IS_BASIC | CLK_GET_RATE_NOCACHE; init.parent_names = &parent_name; init.num_parents = 1; diff --git a/drivers/clk/st/clkgen-mux.c b/drivers/clk/st/clkgen-mux.c index 4fbe6e099587..bd30f8d4e902 100644 --- a/drivers/clk/st/clkgen-mux.c +++ b/drivers/clk/st/clkgen-mux.c @@ -237,7 +237,7 @@ static struct clk *clk_register_genamux(const char *name, init.name = name; init.ops = &clkgena_divmux_ops; - init.flags = CLK_IS_BASIC; + init.flags = CLK_IS_BASIC | CLK_GET_RATE_NOCACHE; init.parent_names = parent_names; init.num_parents = num_parents; @@ -513,7 +513,8 @@ static void __init st_of_clkgena_prediv_setup(struct device_node *np) 0, &clk_name)) return; - clk = clk_register_divider_table(NULL, clk_name, parent_name, 0, + clk = clk_register_divider_table(NULL, clk_name, parent_name, + CLK_GET_RATE_NOCACHE, reg + data->offset, data->shift, 1, 0, data->table, NULL); if (IS_ERR(clk)) @@ -786,7 +787,8 @@ static void __init st_of_clkgen_vcc_setup(struct device_node *np) &mux->hw, &clk_mux_ops, &div->hw, &clk_divider_ops, &gate->hw, &clk_gate_ops, - data->clk_flags); + data->clk_flags | + CLK_GET_RATE_NOCACHE); if (IS_ERR(clk)) { kfree(gate); kfree(div); diff --git a/drivers/clk/st/clkgen-pll.c b/drivers/clk/st/clkgen-pll.c index 106532207213..72d1c27eaffa 100644 --- a/drivers/clk/st/clkgen-pll.c +++ b/drivers/clk/st/clkgen-pll.c @@ -406,7 +406,7 @@ static struct clk * __init clkgen_pll_register(const char *parent_name, init.name = clk_name; init.ops = pll_data->ops; - init.flags = CLK_IS_BASIC; + init.flags = CLK_IS_BASIC | CLK_GET_RATE_NOCACHE; init.parent_names = &parent_name; init.num_parents = 1; -- cgit v1.2.3-70-g09d2 From 3be6d8ce639d92e60d144fb99dd74a53fe3799bb Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Tue, 23 Jun 2015 16:09:25 +0200 Subject: drivers: clk: st: Fix mux bit-setting for Cortex A9 clocks This patch fixes the mux bit-setting for ClockgenA9. Signed-off-by: Gabriel Fernandez Fixes: 13e6f2da1ddf ("clk: st: STiH407: Support for A9 MUX Clocks") Signed-off-by: Stephen Boyd --- drivers/clk/st/clkgen-mux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/st/clkgen-mux.c b/drivers/clk/st/clkgen-mux.c index bd30f8d4e902..717c4a91a17b 100644 --- a/drivers/clk/st/clkgen-mux.c +++ b/drivers/clk/st/clkgen-mux.c @@ -583,7 +583,7 @@ static struct clkgen_mux_data stih416_a9_mux_data = { }; static struct clkgen_mux_data stih407_a9_mux_data = { .offset = 0x1a4, - .shift = 1, + .shift = 0, .width = 2, }; -- cgit v1.2.3-70-g09d2 From 0294112ee3135fbd15eaa70015af8283642dd970 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 4 Jul 2015 03:09:03 +0200 Subject: ACPI / PNP: Reserve ACPI resources at the fs_initcall_sync stage This effectively reverts the following three commits: 7bc10388ccdd ACPI / resources: free memory on error in add_region_before() 0f1b414d1907 ACPI / PNP: Avoid conflicting resource reservations b9a5e5e18fbf ACPI / init: Fix the ordering of acpi_reserve_resources() (commit b9a5e5e18fbf introduced regressions some of which, but not all, were addressed by commit 0f1b414d1907 and commit 7bc10388ccdd was a fixup on top of the latter) and causes ACPI fixed hardware resources to be reserved at the fs_initcall_sync stage of system initialization. The story is as follows. First, a boot regression was reported due to an apparent resource reservation ordering change after a commit that shouldn't lead to such changes. Investigation led to the conclusion that the problem happened because acpi_reserve_resources() was executed at the device_initcall() stage of system initialization which wasn't strictly ordered with respect to driver initialization (and with respect to the initialization of the pcieport driver in particular), so a random change causing the device initcalls to be run in a different order might break things. The response to that was to attempt to run acpi_reserve_resources() as soon as we knew that ACPI would be in use (commit b9a5e5e18fbf). However, that turned out to be too early, because it caused resource reservations made by the PNP system driver to fail on at least one system and that failure was addressed by commit 0f1b414d1907. That fix still turned out to be insufficient, though, because calling acpi_reserve_resources() before the fs_initcall stage of system initialization caused a boot regression to happen on the eCAFE EC-800-H20G/S netbook. That meant that we only could call acpi_reserve_resources() at the fs_initcall initialization stage or later, but then we might just as well call it after the PNP initalization in which case commit 0f1b414d1907 wouldn't be necessary any more. For this reason, the changes made by commit 0f1b414d1907 are reverted (along with a memory leak fixup on top of that commit), the changes made by commit b9a5e5e18fbf that went too far are reverted too and acpi_reserve_resources() is changed into fs_initcall_sync, which will cause it to be executed after the PNP subsystem initialization (which is an fs_initcall) and before device initcalls (including the pcieport driver initialization) which should avoid the initial issue. Link: https://bugzilla.kernel.org/show_bug.cgi?id=100581 Link: http://marc.info/?t=143092384600002&r=1&w=2 Link: https://bugzilla.kernel.org/show_bug.cgi?id=99831 Link: http://marc.info/?t=143389402600001&r=1&w=2 Fixes: b9a5e5e18fbf "ACPI / init: Fix the ordering of acpi_reserve_resources()" Reported-by: Roland Dreier Cc: All applicable Signed-off-by: Rafael J. Wysocki --- drivers/acpi/osl.c | 12 +++- drivers/acpi/resource.c | 162 ------------------------------------------------ drivers/pnp/system.c | 35 +++-------- include/linux/acpi.h | 10 --- 4 files changed, 18 insertions(+), 201 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index c262e4acd68d..3b8963f21b36 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -175,10 +175,14 @@ static void __init acpi_request_region (struct acpi_generic_address *gas, if (!addr || !length) return; - acpi_reserve_region(addr, length, gas->space_id, 0, desc); + /* Resources are never freed */ + if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO) + request_region(addr, length, desc); + else if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) + request_mem_region(addr, length, desc); } -static void __init acpi_reserve_resources(void) +static int __init acpi_reserve_resources(void) { acpi_request_region(&acpi_gbl_FADT.xpm1a_event_block, acpi_gbl_FADT.pm1_event_length, "ACPI PM1a_EVT_BLK"); @@ -207,7 +211,10 @@ static void __init acpi_reserve_resources(void) if (!(acpi_gbl_FADT.gpe1_block_length & 0x1)) acpi_request_region(&acpi_gbl_FADT.xgpe1_block, acpi_gbl_FADT.gpe1_block_length, "ACPI GPE1_BLK"); + + return 0; } +fs_initcall_sync(acpi_reserve_resources); void acpi_os_printf(const char *fmt, ...) { @@ -1862,7 +1869,6 @@ acpi_status __init acpi_os_initialize(void) acpi_status __init acpi_os_initialize1(void) { - acpi_reserve_resources(); kacpid_wq = alloc_workqueue("kacpid", 0, 1); kacpi_notify_wq = alloc_workqueue("kacpi_notify", 0, 1); kacpi_hotplug_wq = alloc_ordered_workqueue("kacpi_hotplug", 0); diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 10561ce16ed1..8244f013f210 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #ifdef CONFIG_X86 @@ -622,164 +621,3 @@ int acpi_dev_filter_resource_type(struct acpi_resource *ares, return (type & types) ? 0 : 1; } EXPORT_SYMBOL_GPL(acpi_dev_filter_resource_type); - -struct reserved_region { - struct list_head node; - u64 start; - u64 end; -}; - -static LIST_HEAD(reserved_io_regions); -static LIST_HEAD(reserved_mem_regions); - -static int request_range(u64 start, u64 end, u8 space_id, unsigned long flags, - char *desc) -{ - unsigned int length = end - start + 1; - struct resource *res; - - res = space_id == ACPI_ADR_SPACE_SYSTEM_IO ? - request_region(start, length, desc) : - request_mem_region(start, length, desc); - if (!res) - return -EIO; - - res->flags &= ~flags; - return 0; -} - -static int add_region_before(u64 start, u64 end, u8 space_id, - unsigned long flags, char *desc, - struct list_head *head) -{ - struct reserved_region *reg; - int error; - - reg = kmalloc(sizeof(*reg), GFP_KERNEL); - if (!reg) - return -ENOMEM; - - error = request_range(start, end, space_id, flags, desc); - if (error) { - kfree(reg); - return error; - } - - reg->start = start; - reg->end = end; - list_add_tail(®->node, head); - return 0; -} - -/** - * acpi_reserve_region - Reserve an I/O or memory region as a system resource. - * @start: Starting address of the region. - * @length: Length of the region. - * @space_id: Identifier of address space to reserve the region from. - * @flags: Resource flags to clear for the region after requesting it. - * @desc: Region description (for messages). - * - * Reserve an I/O or memory region as a system resource to prevent others from - * using it. If the new region overlaps with one of the regions (in the given - * address space) already reserved by this routine, only the non-overlapping - * parts of it will be reserved. - * - * Returned is either 0 (success) or a negative error code indicating a resource - * reservation problem. It is the code of the first encountered error, but the - * routine doesn't abort until it has attempted to request all of the parts of - * the new region that don't overlap with other regions reserved previously. - * - * The resources requested by this routine are never released. - */ -int acpi_reserve_region(u64 start, unsigned int length, u8 space_id, - unsigned long flags, char *desc) -{ - struct list_head *regions; - struct reserved_region *reg; - u64 end = start + length - 1; - int ret = 0, error = 0; - - if (space_id == ACPI_ADR_SPACE_SYSTEM_IO) - regions = &reserved_io_regions; - else if (space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) - regions = &reserved_mem_regions; - else - return -EINVAL; - - if (list_empty(regions)) - return add_region_before(start, end, space_id, flags, desc, regions); - - list_for_each_entry(reg, regions, node) - if (reg->start == end + 1) { - /* The new region can be prepended to this one. */ - ret = request_range(start, end, space_id, flags, desc); - if (!ret) - reg->start = start; - - return ret; - } else if (reg->start > end) { - /* No overlap. Add the new region here and get out. */ - return add_region_before(start, end, space_id, flags, - desc, ®->node); - } else if (reg->end == start - 1) { - goto combine; - } else if (reg->end >= start) { - goto overlap; - } - - /* The new region goes after the last existing one. */ - return add_region_before(start, end, space_id, flags, desc, regions); - - overlap: - /* - * The new region overlaps an existing one. - * - * The head part of the new region immediately preceding the existing - * overlapping one can be combined with it right away. - */ - if (reg->start > start) { - error = request_range(start, reg->start - 1, space_id, flags, desc); - if (error) - ret = error; - else - reg->start = start; - } - - combine: - /* - * The new region is adjacent to an existing one. If it extends beyond - * that region all the way to the next one, it is possible to combine - * all three of them. - */ - while (reg->end < end) { - struct reserved_region *next = NULL; - u64 a = reg->end + 1, b = end; - - if (!list_is_last(®->node, regions)) { - next = list_next_entry(reg, node); - if (next->start <= end) - b = next->start - 1; - } - error = request_range(a, b, space_id, flags, desc); - if (!error) { - if (next && next->start == b + 1) { - reg->end = next->end; - list_del(&next->node); - kfree(next); - } else { - reg->end = end; - break; - } - } else if (next) { - if (!ret) - ret = error; - - reg = next; - } else { - break; - } - } - - return ret ? ret : error; -} -EXPORT_SYMBOL_GPL(acpi_reserve_region); diff --git a/drivers/pnp/system.c b/drivers/pnp/system.c index 515f33882ab8..49c1720df59a 100644 --- a/drivers/pnp/system.c +++ b/drivers/pnp/system.c @@ -7,7 +7,6 @@ * Bjorn Helgaas */ -#include #include #include #include @@ -23,41 +22,25 @@ static const struct pnp_device_id pnp_dev_table[] = { {"", 0} }; -#ifdef CONFIG_ACPI -static bool __reserve_range(u64 start, unsigned int length, bool io, char *desc) -{ - u8 space_id = io ? ACPI_ADR_SPACE_SYSTEM_IO : ACPI_ADR_SPACE_SYSTEM_MEMORY; - return !acpi_reserve_region(start, length, space_id, IORESOURCE_BUSY, desc); -} -#else -static bool __reserve_range(u64 start, unsigned int length, bool io, char *desc) -{ - struct resource *res; - - res = io ? request_region(start, length, desc) : - request_mem_region(start, length, desc); - if (res) { - res->flags &= ~IORESOURCE_BUSY; - return true; - } - return false; -} -#endif - static void reserve_range(struct pnp_dev *dev, struct resource *r, int port) { char *regionid; const char *pnpid = dev_name(&dev->dev); resource_size_t start = r->start, end = r->end; - bool reserved; + struct resource *res; regionid = kmalloc(16, GFP_KERNEL); if (!regionid) return; snprintf(regionid, 16, "pnp %s", pnpid); - reserved = __reserve_range(start, end - start + 1, !!port, regionid); - if (!reserved) + if (port) + res = request_region(start, end - start + 1, regionid); + else + res = request_mem_region(start, end - start + 1, regionid); + if (res) + res->flags &= ~IORESOURCE_BUSY; + else kfree(regionid); /* @@ -66,7 +49,7 @@ static void reserve_range(struct pnp_dev *dev, struct resource *r, int port) * have double reservations. */ dev_info(&dev->dev, "%pR %s reserved\n", r, - reserved ? "has been" : "could not be"); + res ? "has been" : "could not be"); } static void reserve_resources_of_dev(struct pnp_dev *dev) diff --git a/include/linux/acpi.h b/include/linux/acpi.h index c471dfc93b71..fedfd1bea3bf 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -309,9 +309,6 @@ int acpi_check_region(resource_size_t start, resource_size_t n, int acpi_resources_are_enforced(void); -int acpi_reserve_region(u64 start, unsigned int length, u8 space_id, - unsigned long flags, char *desc); - #ifdef CONFIG_HIBERNATION void __init acpi_no_s4_hw_signature(void); #endif @@ -507,13 +504,6 @@ static inline int acpi_check_region(resource_size_t start, resource_size_t n, return 0; } -static inline int acpi_reserve_region(u64 start, unsigned int length, - u8 space_id, unsigned long flags, - char *desc) -{ - return -ENXIO; -} - struct acpi_table_header; static inline int acpi_table_parse(char *id, int (*handler)(struct acpi_table_header *)) -- cgit v1.2.3-70-g09d2 From d3e13ff3c1aa2403d9a5f371baac088daeb8f56d Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 7 Jul 2015 00:31:47 +0200 Subject: ACPI / LPSS: Fix up acpi_lpss_create_device() Fix a return value (which should be a negative error code) and a memory leak (the list allocated by acpi_dev_get_resources() needs to be freed on ioremap() errors too) in acpi_lpss_create_device() introduced by commit 4483d59e29fe 'ACPI / LPSS: check the result of ioremap()'. Fixes: 4483d59e29fe 'ACPI / LPSS: check the result of ioremap()' Reported-by: Dan Carpenter Cc: 4.0+ # 4.0+ Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_lpss.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 569ee090343f..46b58abb08c5 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -352,13 +352,16 @@ static int acpi_lpss_create_device(struct acpi_device *adev, pdata->mmio_size = resource_size(rentry->res); pdata->mmio_base = ioremap(rentry->res->start, pdata->mmio_size); - if (!pdata->mmio_base) - goto err_out; break; } acpi_dev_free_resource_list(&resource_list); + if (!pdata->mmio_base) { + ret = -ENOMEM; + goto err_out; + } + pdata->dev_desc = dev_desc; if (dev_desc->setup) -- cgit v1.2.3-70-g09d2 From 7b2a4635b84b4dbb07c93201a8c0aea82ed65e4f Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Tue, 30 Jun 2015 10:58:44 +0800 Subject: clk: mediatek: mt8173: Fix enabling of critical clocks On the MT8173 the clocks are provided by different units. To enable the critical clocks we must be sure that all parent clocks are already registered, otherwise the parents of the critical clocks end up being unused and get disabled later. To find a place where all parents are registered we try each time after we've registered some clocks if all known providers are present now and only then we enable the critical clocks Signed-off-by: Sascha Hauer Signed-off-by: James Liao [sboyd@codeaurora.org: Marked function and data __init] Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-mt8173.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/mediatek/clk-mt8173.c b/drivers/clk/mediatek/clk-mt8173.c index 4b9e04cdf7e8..8b6523d15fb8 100644 --- a/drivers/clk/mediatek/clk-mt8173.c +++ b/drivers/clk/mediatek/clk-mt8173.c @@ -700,6 +700,22 @@ static const struct mtk_composite peri_clks[] __initconst = { MUX(CLK_PERI_UART3_SEL, "uart3_ck_sel", uart_ck_sel_parents, 0x40c, 3, 1), }; +static struct clk_onecell_data *mt8173_top_clk_data __initdata; +static struct clk_onecell_data *mt8173_pll_clk_data __initdata; + +static void __init mtk_clk_enable_critical(void) +{ + if (!mt8173_top_clk_data || !mt8173_pll_clk_data) + return; + + clk_prepare_enable(mt8173_pll_clk_data->clks[CLK_APMIXED_ARMCA15PLL]); + clk_prepare_enable(mt8173_pll_clk_data->clks[CLK_APMIXED_ARMCA7PLL]); + clk_prepare_enable(mt8173_top_clk_data->clks[CLK_TOP_MEM_SEL]); + clk_prepare_enable(mt8173_top_clk_data->clks[CLK_TOP_DDRPHYCFG_SEL]); + clk_prepare_enable(mt8173_top_clk_data->clks[CLK_TOP_CCI400_SEL]); + clk_prepare_enable(mt8173_top_clk_data->clks[CLK_TOP_RTC_SEL]); +} + static void __init mtk_topckgen_init(struct device_node *node) { struct clk_onecell_data *clk_data; @@ -712,19 +728,19 @@ static void __init mtk_topckgen_init(struct device_node *node) return; } - clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK); + mt8173_top_clk_data = clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK); mtk_clk_register_factors(root_clk_alias, ARRAY_SIZE(root_clk_alias), clk_data); mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), clk_data); mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes), base, &mt8173_clk_lock, clk_data); - clk_prepare_enable(clk_data->clks[CLK_TOP_CCI400_SEL]); - r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); if (r) pr_err("%s(): could not register clock provider: %d\n", __func__, r); + + mtk_clk_enable_critical(); } CLK_OF_DECLARE(mtk_topckgen, "mediatek,mt8173-topckgen", mtk_topckgen_init); @@ -818,13 +834,13 @@ static void __init mtk_apmixedsys_init(struct device_node *node) { struct clk_onecell_data *clk_data; - clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK); + mt8173_pll_clk_data = clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK); if (!clk_data) return; mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); - clk_prepare_enable(clk_data->clks[CLK_APMIXED_ARMCA15PLL]); + mtk_clk_enable_critical(); } CLK_OF_DECLARE(mtk_apmixedsys, "mediatek,mt8173-apmixedsys", mtk_apmixedsys_init); -- cgit v1.2.3-70-g09d2 From 93af5e93544328285a6f65f7d47bbea8979b28fb Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 26 Jun 2015 11:14:14 +0200 Subject: PM / Domains: Avoid infinite loops in attach/detach code If pm_genpd_{add,remove}_device() keeps on failing with -EAGAIN, we end up with an infinite loop in genpd_dev_pm_{at,de}tach(). This may happen due to a genpd.prepared_count imbalance. This is a bug elsewhere, but it will result in a system lock up, possibly during reboot of an otherwise functioning system. To avoid this, put a limit on the maximum number of loop iterations, using an exponential back-off mechanism. If the limit is reached, the operation will just fail. An error message is already printed. Signed-off-by: Geert Uytterhoeven Signed-off-by: Rafael J. Wysocki --- drivers/base/power/domain.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index cdd547bd67df..0ee43c1056e0 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -6,6 +6,7 @@ * This file is released under the GPLv2. */ +#include #include #include #include @@ -19,6 +20,8 @@ #include #include +#define GENPD_RETRY_MAX_MS 250 /* Approximate */ + #define GENPD_DEV_CALLBACK(genpd, type, callback, dev) \ ({ \ type (*__routine)(struct device *__d); \ @@ -2131,6 +2134,7 @@ EXPORT_SYMBOL_GPL(of_genpd_get_from_provider); static void genpd_dev_pm_detach(struct device *dev, bool power_off) { struct generic_pm_domain *pd; + unsigned int i; int ret = 0; pd = pm_genpd_lookup_dev(dev); @@ -2139,10 +2143,12 @@ static void genpd_dev_pm_detach(struct device *dev, bool power_off) dev_dbg(dev, "removing from PM domain %s\n", pd->name); - while (1) { + for (i = 1; i < GENPD_RETRY_MAX_MS; i <<= 1) { ret = pm_genpd_remove_device(pd, dev); if (ret != -EAGAIN) break; + + mdelay(i); cond_resched(); } @@ -2183,6 +2189,7 @@ int genpd_dev_pm_attach(struct device *dev) { struct of_phandle_args pd_args; struct generic_pm_domain *pd; + unsigned int i; int ret; if (!dev->of_node) @@ -2218,10 +2225,12 @@ int genpd_dev_pm_attach(struct device *dev) dev_dbg(dev, "adding to PM domain %s\n", pd->name); - while (1) { + for (i = 1; i < GENPD_RETRY_MAX_MS; i <<= 1) { ret = pm_genpd_add_device(pd, dev); if (ret != -EAGAIN) break; + + mdelay(i); cond_resched(); } -- cgit v1.2.3-70-g09d2 From 26095a01d359827eeccec5459c28ddd976183179 Mon Sep 17 00:00:00 2001 From: "Suthikulpanit, Suravee" Date: Tue, 7 Jul 2015 01:55:20 +0200 Subject: ACPI / scan: Add support for ACPI _CLS device matching Device drivers typically use ACPI _HIDs/_CIDs listed in struct device_driver acpi_match_table to match devices. However, for generic drivers, we do not want to list _HID for all supported devices. Also, certain classes of devices do not have _CID (e.g. SATA, USB). Instead, we can leverage ACPI _CLS, which specifies PCI-defined class code (i.e. base-class, subclass and programming interface). This patch adds support for matching ACPI devices using the _CLS method. To support loadable module, current design uses _HID or _CID to match device's modalias. With the new way of matching with _CLS this would requires modification to the current ACPI modalias key to include _CLS. This patch appends PCI-defined class-code to the existing ACPI modalias as following. acpi::::..::: E.g: # cat /sys/devices/platform/AMDI0600:00/modalias acpi:AMDI0600:010601: where bb is th base-class code, ss is te sub-class code, and pp is the programming interface code Since there would not be _HID/_CID in the ACPI matching table of the driver, this patch adds a field to acpi_device_id to specify the matching _CLS. static const struct acpi_device_id ahci_acpi_match[] = { { ACPI_DEVICE_CLASS(PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff) }, {}, }; In this case, the corresponded entry in modules.alias file would be: alias acpi*:010601:* ahci_platform Acked-by: Mika Westerberg Reviewed-by: Hanjun Guo Signed-off-by: Suravee Suthikulpanit Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 32 ++++++++++++++++++++++++++++++-- include/linux/acpi.h | 14 ++++++++++++++ include/linux/mod_devicetable.h | 2 ++ scripts/mod/devicetable-offsets.c | 2 ++ scripts/mod/file2alias.c | 32 ++++++++++++++++++++++++++++++-- 5 files changed, 78 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 2649a068671d..ec256352f423 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1019,6 +1019,29 @@ static bool acpi_of_match_device(struct acpi_device *adev, return false; } +static bool __acpi_match_device_cls(const struct acpi_device_id *id, + struct acpi_hardware_id *hwid) +{ + int i, msk, byte_shift; + char buf[3]; + + if (!id->cls) + return false; + + /* Apply class-code bitmask, before checking each class-code byte */ + for (i = 1; i <= 3; i++) { + byte_shift = 8 * (3 - i); + msk = (id->cls_msk >> byte_shift) & 0xFF; + if (!msk) + continue; + + sprintf(buf, "%02x", (id->cls >> byte_shift) & msk); + if (strncmp(buf, &hwid->id[(i - 1) * 2], 2)) + return false; + } + return true; +} + static const struct acpi_device_id *__acpi_match_device( struct acpi_device *device, const struct acpi_device_id *ids, @@ -1036,9 +1059,12 @@ static const struct acpi_device_id *__acpi_match_device( list_for_each_entry(hwid, &device->pnp.ids, list) { /* First, check the ACPI/PNP IDs provided by the caller. */ - for (id = ids; id->id[0]; id++) - if (!strcmp((char *) id->id, hwid->id)) + for (id = ids; id->id[0] || id->cls; id++) { + if (id->id[0] && !strcmp((char *) id->id, hwid->id)) return id; + else if (id->cls && __acpi_match_device_cls(id, hwid)) + return id; + } /* * Next, check ACPI_DT_NAMESPACE_HID and try to match the @@ -2101,6 +2127,8 @@ static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp, if (info->valid & ACPI_VALID_UID) pnp->unique_id = kstrdup(info->unique_id.string, GFP_KERNEL); + if (info->valid & ACPI_VALID_CLS) + acpi_add_id(pnp, info->class_code.string); kfree(info); diff --git a/include/linux/acpi.h b/include/linux/acpi.h index c471dfc93b71..bdfdb9f65c23 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -58,6 +58,19 @@ static inline acpi_handle acpi_device_handle(struct acpi_device *adev) acpi_fwnode_handle(adev) : NULL) #define ACPI_HANDLE(dev) acpi_device_handle(ACPI_COMPANION(dev)) +/** + * ACPI_DEVICE_CLASS - macro used to describe an ACPI device with + * the PCI-defined class-code information + * + * @_cls : the class, subclass, prog-if triple for this device + * @_msk : the class mask for this device + * + * This macro is used to create a struct acpi_device_id that matches a + * specific PCI class. The .id and .driver_data fields will be left + * initialized with the default value. + */ +#define ACPI_DEVICE_CLASS(_cls, _msk) .cls = (_cls), .cls_msk = (_msk), + static inline bool has_acpi_companion(struct device *dev) { return is_acpi_node(dev->fwnode); @@ -446,6 +459,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *); #define ACPI_COMPANION(dev) (NULL) #define ACPI_COMPANION_SET(dev, adev) do { } while (0) #define ACPI_HANDLE(dev) (NULL) +#define ACPI_DEVICE_CLASS(_cls, _msk) .cls = (0), .cls_msk = (0), struct fwnode_handle; diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index 8183d6640ca7..34f25b7bf642 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -189,6 +189,8 @@ struct css_device_id { struct acpi_device_id { __u8 id[ACPI_ID_LEN]; kernel_ulong_t driver_data; + __u32 cls; + __u32 cls_msk; }; #define PNP_ID_LEN 8 diff --git a/scripts/mod/devicetable-offsets.c b/scripts/mod/devicetable-offsets.c index eff7de1fc82e..e70fcd12eeeb 100644 --- a/scripts/mod/devicetable-offsets.c +++ b/scripts/mod/devicetable-offsets.c @@ -63,6 +63,8 @@ int main(void) DEVID(acpi_device_id); DEVID_FIELD(acpi_device_id, id); + DEVID_FIELD(acpi_device_id, cls); + DEVID_FIELD(acpi_device_id, cls_msk); DEVID(pnp_device_id); DEVID_FIELD(pnp_device_id, id); diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 84c86f3cd6cd..5f2088209132 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -523,12 +523,40 @@ static int do_serio_entry(const char *filename, } ADD_TO_DEVTABLE("serio", serio_device_id, do_serio_entry); -/* looks like: "acpi:ACPI0003 or acpi:PNP0C0B" or "acpi:LNXVIDEO" */ +/* looks like: "acpi:ACPI0003" or "acpi:PNP0C0B" or "acpi:LNXVIDEO" or + * "acpi:bbsspp" (bb=base-class, ss=sub-class, pp=prog-if) + * + * NOTE: Each driver should use one of the following : _HID, _CIDs + * or _CLS. Also, bb, ss, and pp can be substituted with ?? + * as don't care byte. + */ static int do_acpi_entry(const char *filename, void *symval, char *alias) { DEF_FIELD_ADDR(symval, acpi_device_id, id); - sprintf(alias, "acpi*:%s:*", *id); + DEF_FIELD_ADDR(symval, acpi_device_id, cls); + DEF_FIELD_ADDR(symval, acpi_device_id, cls_msk); + + if (id && strlen((const char *)*id)) + sprintf(alias, "acpi*:%s:*", *id); + else if (cls) { + int i, byte_shift, cnt = 0; + unsigned int msk; + + sprintf(&alias[cnt], "acpi*:"); + cnt = 6; + for (i = 1; i <= 3; i++) { + byte_shift = 8 * (3-i); + msk = (*cls_msk >> byte_shift) & 0xFF; + if (msk) + sprintf(&alias[cnt], "%02x", + (*cls >> byte_shift) & 0xFF); + else + sprintf(&alias[cnt], "??"); + cnt += 2; + } + sprintf(&alias[cnt], ":*"); + } return 1; } ADD_TO_DEVTABLE("acpi", acpi_device_id, do_acpi_entry); -- cgit v1.2.3-70-g09d2 From 2051e9248688e4c36e4de2e93b88fa0d74e86261 Mon Sep 17 00:00:00 2001 From: "Suthikulpanit, Suravee" Date: Tue, 7 Jul 2015 01:55:21 +0200 Subject: ata: ahci_platform: Add ACPI _CLS matching This patch adds ACPI supports for AHCI platform driver, which uses _CLS method to match the device. The following is an example of ASL structure in DSDT for a SATA controller, which contains _CLS package to be matched by the ahci_platform driver: Device (AHC0) // AHCI Controller { Name(_HID, "AMDI0600") Name (_CCA, 1) Name (_CLS, Package (3) { 0x01, // Base Class: Mass Storage 0x06, // Sub-Class: serial ATA 0x01, // Interface: AHCI }) Name (_CRS, ResourceTemplate () { Memory32Fixed (ReadWrite, 0xE0300000, 0x00010000) Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive,,,) { 387 } }) } Also, since ATA driver should not require PCI support for ATA_ACPI, this patch removes dependency in the driver/ata/Kconfig. Acked-by: Tejun Heo Acked-by: Mika Westerberg Reviewed-by: Hanjun Guo Signed-off-by: Suravee Suthikulpanit Signed-off-by: Rafael J. Wysocki --- drivers/ata/Kconfig | 2 +- drivers/ata/ahci_platform.c | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 6d17a3b65ef7..15e40ee62a94 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -48,7 +48,7 @@ config ATA_VERBOSE_ERROR config ATA_ACPI bool "ATA ACPI Support" - depends on ACPI && PCI + depends on ACPI default y help This option adds support for ATA-related ACPI objects. diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c index 614c78f510f0..1befb114c384 100644 --- a/drivers/ata/ahci_platform.c +++ b/drivers/ata/ahci_platform.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include "ahci.h" #define DRV_NAME "ahci" @@ -79,12 +81,19 @@ static const struct of_device_id ahci_of_match[] = { }; MODULE_DEVICE_TABLE(of, ahci_of_match); +static const struct acpi_device_id ahci_acpi_match[] = { + { ACPI_DEVICE_CLASS(PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff) }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, ahci_acpi_match); + static struct platform_driver ahci_driver = { .probe = ahci_probe, .remove = ata_platform_remove_one, .driver = { .name = DRV_NAME, .of_match_table = ahci_of_match, + .acpi_match_table = ahci_acpi_match, .pm = &ahci_pm_ops, }, }; -- cgit v1.2.3-70-g09d2 From 747d34e7313034768aac83d679db43cedc5ab778 Mon Sep 17 00:00:00 2001 From: Philippe Reynes Date: Sat, 27 Jun 2015 23:11:44 +0200 Subject: clocksource/imx: Define clocksource for mx27 The rework of the imx clocksource driver missed to add an entry for imx27 which results in a boot failure on those machines. Add the proper CLOCKSOURCE_OF_DECLARE() entry for imx27 and map it to the imx21 init. Fixes: bef11c881ba5 'ARM: imx: initialize gpt device type for DT boot' Signed-off-by: Philippe Reynes Cc: linux-arm-kernel@lists.infradead.org Cc: daniel.lezcano@linaro.org Cc: fabio.estevam@freescale.com Cc: shawnguo@kernel.org Cc: kernel@pengutronix.de Link: http://lkml.kernel.org/r/1435439504-406-1-git-send-email-tremyfr@gmail.com Signed-off-by: Thomas Gleixner --- drivers/clocksource/timer-imx-gpt.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/clocksource/timer-imx-gpt.c b/drivers/clocksource/timer-imx-gpt.c index 879c78423546..2d59038dec43 100644 --- a/drivers/clocksource/timer-imx-gpt.c +++ b/drivers/clocksource/timer-imx-gpt.c @@ -529,6 +529,7 @@ static void __init imx6dl_timer_init_dt(struct device_node *np) CLOCKSOURCE_OF_DECLARE(imx1_timer, "fsl,imx1-gpt", imx1_timer_init_dt); CLOCKSOURCE_OF_DECLARE(imx21_timer, "fsl,imx21-gpt", imx21_timer_init_dt); +CLOCKSOURCE_OF_DECLARE(imx27_timer, "fsl,imx27-gpt", imx21_timer_init_dt); CLOCKSOURCE_OF_DECLARE(imx31_timer, "fsl,imx31-gpt", imx31_timer_init_dt); CLOCKSOURCE_OF_DECLARE(imx25_timer, "fsl,imx25-gpt", imx31_timer_init_dt); CLOCKSOURCE_OF_DECLARE(imx50_timer, "fsl,imx50-gpt", imx31_timer_init_dt); -- cgit v1.2.3-70-g09d2 From 3f8dc44d88d3e86178eb9322c779c599f3745b21 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Tue, 7 Jul 2015 11:01:17 +1000 Subject: cxl: Fix refcounting in kernel API Currently the kernel API AFU dev refcounting is done on context start and stop. This patch moves this refcounting to context init and release, bringing it inline with how the userspace API does it. Without this we've seen the refcounting on the AFU get out of whack between the user and kernel API usage. This causes the AFU structures to be freed when they are actually still in use. This fixes some kref warnings we've been seeing and spurious ErrIVTE IRQs. Signed-off-by: Michael Neuling Acked-by: Ian Munsie Signed-off-by: Michael Ellerman --- drivers/misc/cxl/api.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/cxl/api.c b/drivers/misc/cxl/api.c index 0c77240ae2fc..729e0851167d 100644 --- a/drivers/misc/cxl/api.c +++ b/drivers/misc/cxl/api.c @@ -23,6 +23,7 @@ struct cxl_context *cxl_dev_context_init(struct pci_dev *dev) afu = cxl_pci_to_afu(dev); + get_device(&afu->dev); ctx = cxl_context_alloc(); if (IS_ERR(ctx)) return ctx; @@ -31,6 +32,7 @@ struct cxl_context *cxl_dev_context_init(struct pci_dev *dev) rc = cxl_context_init(ctx, afu, false, NULL); if (rc) { kfree(ctx); + put_device(&afu->dev); return ERR_PTR(-ENOMEM); } cxl_assign_psn_space(ctx); @@ -60,6 +62,8 @@ int cxl_release_context(struct cxl_context *ctx) if (ctx->status != CLOSED) return -EBUSY; + put_device(&ctx->afu->dev); + cxl_context_free(ctx); return 0; @@ -159,7 +163,6 @@ int cxl_start_context(struct cxl_context *ctx, u64 wed, } ctx->status = STARTED; - get_device(&ctx->afu->dev); out: mutex_unlock(&ctx->status_mutex); return rc; @@ -175,12 +178,7 @@ EXPORT_SYMBOL_GPL(cxl_process_element); /* Stop a context. Returns 0 on success, otherwise -Errno */ int cxl_stop_context(struct cxl_context *ctx) { - int rc; - - rc = __detach_context(ctx); - if (!rc) - put_device(&ctx->afu->dev); - return rc; + return __detach_context(ctx); } EXPORT_SYMBOL_GPL(cxl_stop_context); -- cgit v1.2.3-70-g09d2 From 6d3dab7d84177f836b14961b4d252d0959d66768 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 7 Jul 2015 13:08:39 +0200 Subject: PM / wakeirq: Avoid setting power.wakeirq too hastily If dev_pm_attach_wake_irq() fails, the device's power.wakeirq field should not be set to point to the struct wake_irq passed to that function, as that object will be freed going forward. For this reason, make dev_pm_attach_wake_irq() first call device_wakeup_attach_irq() and only set the device's power.wakeirq field if that's successful. That requires device_wakeup_attach_irq() to be called under the device's power.lock lock, but since dev_pm_attach_wake_irq() is the only caller of it, the requisite changes are easy to make. Fixes: 4990d4fe327b (PM / Wakeirq: Add automated device wake IRQ handling) Reported-by: Felipe Balbi Tested-by: Tony Lindgren Signed-off-by: Rafael J. Wysocki --- drivers/base/power/wakeirq.c | 12 +++++------- drivers/base/power/wakeup.c | 31 ++++++++++--------------------- 2 files changed, 15 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/base/power/wakeirq.c b/drivers/base/power/wakeirq.c index 7470004ca810..eb6e67451dec 100644 --- a/drivers/base/power/wakeirq.c +++ b/drivers/base/power/wakeirq.c @@ -45,14 +45,12 @@ static int dev_pm_attach_wake_irq(struct device *dev, int irq, return -EEXIST; } - dev->power.wakeirq = wirq; - spin_unlock_irqrestore(&dev->power.lock, flags); - err = device_wakeup_attach_irq(dev, wirq); - if (err) - return err; + if (!err) + dev->power.wakeirq = wirq; - return 0; + spin_unlock_irqrestore(&dev->power.lock, flags); + return err; } /** @@ -105,10 +103,10 @@ void dev_pm_clear_wake_irq(struct device *dev) return; spin_lock_irqsave(&dev->power.lock, flags); + device_wakeup_detach_irq(dev); dev->power.wakeirq = NULL; spin_unlock_irqrestore(&dev->power.lock, flags); - device_wakeup_detach_irq(dev); if (wirq->dedicated_irq) free_irq(wirq->irq, wirq); kfree(wirq); diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index 7332ebc9cab0..15d27d782dc1 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -247,32 +247,25 @@ EXPORT_SYMBOL_GPL(device_wakeup_enable); * Attach a device wakeirq to the wakeup source so the device * wake IRQ can be configured automatically for suspend and * resume. + * + * Call under the device's power.lock lock. */ int device_wakeup_attach_irq(struct device *dev, struct wake_irq *wakeirq) { struct wakeup_source *ws; - int ret = 0; - spin_lock_irq(&dev->power.lock); ws = dev->power.wakeup; if (!ws) { dev_err(dev, "forgot to call call device_init_wakeup?\n"); - ret = -EINVAL; - goto unlock; + return -EINVAL; } - if (ws->wakeirq) { - ret = -EEXIST; - goto unlock; - } + if (ws->wakeirq) + return -EEXIST; ws->wakeirq = wakeirq; - -unlock: - spin_unlock_irq(&dev->power.lock); - - return ret; + return 0; } /** @@ -280,20 +273,16 @@ unlock: * @dev: Device to handle * * Removes a device wakeirq from the wakeup source. + * + * Call under the device's power.lock lock. */ void device_wakeup_detach_irq(struct device *dev) { struct wakeup_source *ws; - spin_lock_irq(&dev->power.lock); ws = dev->power.wakeup; - if (!ws) - goto unlock; - - ws->wakeirq = NULL; - -unlock: - spin_unlock_irq(&dev->power.lock); + if (ws) + ws->wakeirq = NULL; } /** -- cgit v1.2.3-70-g09d2 From 99e3e3ae332b6ca91d5c444ea7849f367f5e5a76 Mon Sep 17 00:00:00 2001 From: Al Stone Date: Mon, 6 Jul 2015 17:16:48 -0600 Subject: ACPI / ARM64 : use the new BAD_MADT_GICC_ENTRY macro For those parts of the arm64 ACPI code that need to check GICC subtables in the MADT, use the new BAD_MADT_GICC_ENTRY macro instead of the previous BAD_MADT_ENTRY. The new macro takes into account differences in the size of the GICC subtable that the old macro did not; this caused failures even though the subtable entries are valid. Fixes: aeb823bbacc2 ("ACPICA: ACPI 6.0: Add changes for FADT table.") Signed-off-by: Al Stone Reviewed-by: Hanjun Guo Acked-by: Will Deacon Acked-by: "Rafael J. Wysocki" Signed-off-by: Catalin Marinas --- arch/arm64/kernel/smp.c | 2 +- drivers/irqchip/irq-gic.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index 695801a54ca5..50fb4696654e 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -438,7 +438,7 @@ acpi_parse_gic_cpu_interface(struct acpi_subtable_header *header, struct acpi_madt_generic_interrupt *processor; processor = (struct acpi_madt_generic_interrupt *)header; - if (BAD_MADT_ENTRY(processor, end)) + if (BAD_MADT_GICC_ENTRY(processor, end)) return -EINVAL; acpi_table_print_madt_entry(header); diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 8d7e1c8b6d56..4dd88264dff5 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -1055,7 +1055,7 @@ gic_acpi_parse_madt_cpu(struct acpi_subtable_header *header, processor = (struct acpi_madt_generic_interrupt *)header; - if (BAD_MADT_ENTRY(processor, end)) + if (BAD_MADT_GICC_ENTRY(processor, end)) return -EINVAL; /* -- cgit v1.2.3-70-g09d2 From 539c4b88146cc320aee18b08ebb43ab57d523dcc Mon Sep 17 00:00:00 2001 From: duson Date: Tue, 7 Jul 2015 10:25:39 -0700 Subject: Input: elan_i2c - change the hover event from MT to ST The firmware only reports hover condition while the very first contact is approaching the surface; the hover is not reported for the subsequent contacts. Therefore we should not be using ABS_MT_DISTANCE to report hover but rather its single-touch counterpart ABS_DISTANCE. Signed-off-by: Duson Lin Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elan_i2c_core.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index 62641f2adaf7..5b5f403d8ce6 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -771,7 +771,7 @@ static const struct attribute_group *elan_sysfs_groups[] = { */ static void elan_report_contact(struct elan_tp_data *data, int contact_num, bool contact_valid, - bool hover_event, u8 *finger_data) + u8 *finger_data) { struct input_dev *input = data->input; unsigned int pos_x, pos_y; @@ -815,9 +815,7 @@ static void elan_report_contact(struct elan_tp_data *data, input_mt_report_slot_state(input, MT_TOOL_FINGER, true); input_report_abs(input, ABS_MT_POSITION_X, pos_x); input_report_abs(input, ABS_MT_POSITION_Y, data->max_y - pos_y); - input_report_abs(input, ABS_MT_DISTANCE, hover_event); - input_report_abs(input, ABS_MT_PRESSURE, - hover_event ? 0 : scaled_pressure); + input_report_abs(input, ABS_MT_PRESSURE, scaled_pressure); input_report_abs(input, ABS_TOOL_WIDTH, mk_x); input_report_abs(input, ABS_MT_TOUCH_MAJOR, major); input_report_abs(input, ABS_MT_TOUCH_MINOR, minor); @@ -839,14 +837,14 @@ static void elan_report_absolute(struct elan_tp_data *data, u8 *packet) hover_event = hover_info & 0x40; for (i = 0; i < ETP_MAX_FINGERS; i++) { contact_valid = tp_info & (1U << (3 + i)); - elan_report_contact(data, i, contact_valid, hover_event, - finger_data); + elan_report_contact(data, i, contact_valid, finger_data); if (contact_valid) finger_data += ETP_FINGER_DATA_LEN; } input_report_key(input, BTN_LEFT, tp_info & 0x01); + input_report_abs(input, ABS_DISTANCE, hover_event != 0); input_mt_report_pointer_emulation(input, true); input_sync(input); } @@ -922,6 +920,7 @@ static int elan_setup_input_device(struct elan_tp_data *data) input_abs_set_res(input, ABS_Y, data->y_res); input_set_abs_params(input, ABS_PRESSURE, 0, ETP_MAX_PRESSURE, 0, 0); input_set_abs_params(input, ABS_TOOL_WIDTH, 0, ETP_FINGER_WIDTH, 0, 0); + input_set_abs_params(input, ABS_DISTANCE, 0, 1, 0, 0); /* And MT parameters */ input_set_abs_params(input, ABS_MT_POSITION_X, 0, data->max_x, 0, 0); @@ -934,7 +933,6 @@ static int elan_setup_input_device(struct elan_tp_data *data) ETP_FINGER_WIDTH * max_width, 0, 0); input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, ETP_FINGER_WIDTH * min_width, 0, 0); - input_set_abs_params(input, ABS_MT_DISTANCE, 0, 1, 0, 0); data->input = input; -- cgit v1.2.3-70-g09d2 From 0bb383a2d8f51e32ecc156f3f84067420ffe6d20 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 7 Jul 2015 20:56:04 +0200 Subject: MIPS, CPUFREQ: Fix spelling of Institute. Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mach-loongson64/mmzone.h | 2 +- arch/mips/loongson64/common/bonito-irq.c | 2 +- arch/mips/loongson64/common/cmdline.c | 2 +- arch/mips/loongson64/common/cs5536/cs5536_mfgpt.c | 2 +- arch/mips/loongson64/common/env.c | 2 +- arch/mips/loongson64/common/irq.c | 2 +- arch/mips/loongson64/common/setup.c | 2 +- arch/mips/loongson64/fuloong-2e/irq.c | 2 +- arch/mips/loongson64/lemote-2f/clock.c | 2 +- arch/mips/loongson64/loongson-3/numa.c | 2 +- drivers/cpufreq/loongson2_cpufreq.c | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/arch/mips/include/asm/mach-loongson64/mmzone.h b/arch/mips/include/asm/mach-loongson64/mmzone.h index 37c08a27b4f0..c9f7e231e66b 100644 --- a/arch/mips/include/asm/mach-loongson64/mmzone.h +++ b/arch/mips/include/asm/mach-loongson64/mmzone.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2010 Loongson Inc. & Lemote Inc. & - * Insititute of Computing Technology + * Institute of Computing Technology * Author: Xiang Gao, gaoxiang@ict.ac.cn * Huacai Chen, chenhc@lemote.com * Xiaofu Meng, Shuangshuang Zhang diff --git a/arch/mips/loongson64/common/bonito-irq.c b/arch/mips/loongson64/common/bonito-irq.c index cc0e4fd548e6..4e116d23bab3 100644 --- a/arch/mips/loongson64/common/bonito-irq.c +++ b/arch/mips/loongson64/common/bonito-irq.c @@ -3,7 +3,7 @@ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net * Copyright (C) 2000, 2001 Ralf Baechle (ralf@gnu.org) * - * Copyright (C) 2007 Lemote Inc. & Insititute of Computing Technology + * Copyright (C) 2007 Lemote Inc. & Institute of Computing Technology * Author: Fuxin Zhang, zhangfx@lemote.com * * This program is free software; you can redistribute it and/or modify it diff --git a/arch/mips/loongson64/common/cmdline.c b/arch/mips/loongson64/common/cmdline.c index 72fed003a536..01fbed137028 100644 --- a/arch/mips/loongson64/common/cmdline.c +++ b/arch/mips/loongson64/common/cmdline.c @@ -6,7 +6,7 @@ * Copyright 2003 ICT CAS * Author: Michael Guo * - * Copyright (C) 2007 Lemote Inc. & Insititute of Computing Technology + * Copyright (C) 2007 Lemote Inc. & Institute of Computing Technology * Author: Fuxin Zhang, zhangfx@lemote.com * * Copyright (C) 2009 Lemote Inc. diff --git a/arch/mips/loongson64/common/cs5536/cs5536_mfgpt.c b/arch/mips/loongson64/common/cs5536/cs5536_mfgpt.c index 12c75db23420..875037063a80 100644 --- a/arch/mips/loongson64/common/cs5536/cs5536_mfgpt.c +++ b/arch/mips/loongson64/common/cs5536/cs5536_mfgpt.c @@ -1,7 +1,7 @@ /* * CS5536 General timer functions * - * Copyright (C) 2007 Lemote Inc. & Insititute of Computing Technology + * Copyright (C) 2007 Lemote Inc. & Institute of Computing Technology * Author: Yanhua, yanh@lemote.com * * Copyright (C) 2009 Lemote Inc. diff --git a/arch/mips/loongson64/common/env.c b/arch/mips/loongson64/common/env.c index 22f04ca2ff3e..f6c44dd332e2 100644 --- a/arch/mips/loongson64/common/env.c +++ b/arch/mips/loongson64/common/env.c @@ -6,7 +6,7 @@ * Copyright 2003 ICT CAS * Author: Michael Guo * - * Copyright (C) 2007 Lemote Inc. & Insititute of Computing Technology + * Copyright (C) 2007 Lemote Inc. & Institute of Computing Technology * Author: Fuxin Zhang, zhangfx@lemote.com * * Copyright (C) 2009 Lemote Inc. diff --git a/arch/mips/loongson64/common/irq.c b/arch/mips/loongson64/common/irq.c index 687003b19b45..d36d969a4a87 100644 --- a/arch/mips/loongson64/common/irq.c +++ b/arch/mips/loongson64/common/irq.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 Lemote Inc. & Insititute of Computing Technology + * Copyright (C) 2007 Lemote Inc. & Institute of Computing Technology * Author: Fuxin Zhang, zhangfx@lemote.com * * This program is free software; you can redistribute it and/or modify it diff --git a/arch/mips/loongson64/common/setup.c b/arch/mips/loongson64/common/setup.c index d477dd6bb326..2dc5122f0e09 100644 --- a/arch/mips/loongson64/common/setup.c +++ b/arch/mips/loongson64/common/setup.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 Lemote Inc. & Insititute of Computing Technology + * Copyright (C) 2007 Lemote Inc. & Institute of Computing Technology * Author: Fuxin Zhang, zhangfx@lemote.com * * This program is free software; you can redistribute it and/or modify it diff --git a/arch/mips/loongson64/fuloong-2e/irq.c b/arch/mips/loongson64/fuloong-2e/irq.c index ef5ec8f3de5f..892963f860b7 100644 --- a/arch/mips/loongson64/fuloong-2e/irq.c +++ b/arch/mips/loongson64/fuloong-2e/irq.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 Lemote Inc. & Insititute of Computing Technology + * Copyright (C) 2007 Lemote Inc. & Institute of Computing Technology * Author: Fuxin Zhang, zhangfx@lemote.com * * This program is free software; you can redistribute it and/or modify it diff --git a/arch/mips/loongson64/lemote-2f/clock.c b/arch/mips/loongson64/lemote-2f/clock.c index 4c5b94af3643..a78fb657068c 100644 --- a/arch/mips/loongson64/lemote-2f/clock.c +++ b/arch/mips/loongson64/lemote-2f/clock.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 - 2008 Lemote Inc. & Insititute of Computing Technology + * Copyright (C) 2006 - 2008 Lemote Inc. & Institute of Computing Technology * Author: Yanhua, yanh@lemote.com * * This file is subject to the terms and conditions of the GNU General Public diff --git a/arch/mips/loongson64/loongson-3/numa.c b/arch/mips/loongson64/loongson-3/numa.c index 12d14ed48778..6f9e010cec4d 100644 --- a/arch/mips/loongson64/loongson-3/numa.c +++ b/arch/mips/loongson64/loongson-3/numa.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2010 Loongson Inc. & Lemote Inc. & - * Insititute of Computing Technology + * Institute of Computing Technology * Author: Xiang Gao, gaoxiang@ict.ac.cn * Huacai Chen, chenhc@lemote.com * Xiaofu Meng, Shuangshuang Zhang diff --git a/drivers/cpufreq/loongson2_cpufreq.c b/drivers/cpufreq/loongson2_cpufreq.c index fc897babab55..e362860c2b50 100644 --- a/drivers/cpufreq/loongson2_cpufreq.c +++ b/drivers/cpufreq/loongson2_cpufreq.c @@ -3,7 +3,7 @@ * * The 2E revision of loongson processor not support this feature. * - * Copyright (C) 2006 - 2008 Lemote Inc. & Insititute of Computing Technology + * Copyright (C) 2006 - 2008 Lemote Inc. & Institute of Computing Technology * Author: Yanhua, yanh@lemote.com * * This file is subject to the terms and conditions of the GNU General Public -- cgit v1.2.3-70-g09d2 From 4f273959b850569253299987eee611927f048de7 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 8 Jul 2015 00:22:03 +0300 Subject: mei: nfc: fix deadlock on shutdown/suspend path In function mei_nfc_host_exit mei_cl_remove_device cannot be called under the device mutex as device removing flow invokes the device driver remove handler that calls in turn to mei_cl_disable_device which naturally acquires the device mutex. Also remove mei_cl_bus_remove_devices which has the same issue, but is never executed as currently the only device on the mei client bus is NFC and a new device cannot be easily added till the bus revamp is completed. This fixes regression caused by commit be9b720a0ccb ("mei_phy: move all nfc logic from mei driver to nfc") Prior to this change the nfc driver remove handler called to no-op disable function while actual nfc device was disabled directly from the mei driver. Reported-by: Linus Torvalds Acked-by: Greg Kroah-Hartman Cc: Samuel Ortiz Signed-off-by: Tomas Winkler Signed-off-by: Linus Torvalds --- drivers/misc/mei/bus.c | 16 ---------------- drivers/misc/mei/init.c | 2 -- drivers/misc/mei/nfc.c | 3 ++- 3 files changed, 2 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 357b6ae4d207..458aa5a09c52 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -552,22 +552,6 @@ void mei_cl_bus_rx_event(struct mei_cl *cl) schedule_work(&device->event_work); } -void mei_cl_bus_remove_devices(struct mei_device *dev) -{ - struct mei_cl *cl, *next; - - mutex_lock(&dev->device_lock); - list_for_each_entry_safe(cl, next, &dev->device_list, device_link) { - if (cl->device) - mei_cl_remove_device(cl->device); - - list_del(&cl->device_link); - mei_cl_unlink(cl); - kfree(cl); - } - mutex_unlock(&dev->device_lock); -} - int __init mei_cl_bus_init(void) { return bus_register(&mei_cl_bus_type); diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index 94514b2c7a50..00c3865ca3b1 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c @@ -333,8 +333,6 @@ void mei_stop(struct mei_device *dev) mei_nfc_host_exit(dev); - mei_cl_bus_remove_devices(dev); - mutex_lock(&dev->device_lock); mei_wd_stop(dev); diff --git a/drivers/misc/mei/nfc.c b/drivers/misc/mei/nfc.c index b983c4ecad38..290ef3037437 100644 --- a/drivers/misc/mei/nfc.c +++ b/drivers/misc/mei/nfc.c @@ -402,11 +402,12 @@ void mei_nfc_host_exit(struct mei_device *dev) cldev->priv_data = NULL; - mutex_lock(&dev->device_lock); /* Need to remove the device here * since mei_nfc_free will unlink the clients */ mei_cl_remove_device(cldev); + + mutex_lock(&dev->device_lock); mei_nfc_free(ndev); mutex_unlock(&dev->device_lock); } -- cgit v1.2.3-70-g09d2 From 56551da9255f20ffd3a9711728a1a3ad4b7100af Mon Sep 17 00:00:00 2001 From: Pankaj Dev Date: Tue, 7 Jul 2015 09:40:50 +0200 Subject: drivers: clk: st: Incorrect register offset used for lock_status Incorrect register offset used for sthi407 clockgenC Signed-off-by: Pankaj Dev Signed-off-by: Gabriel Fernandez Fixes: 51306d56ba81 ("clk: st: STiH407: Support for clockgenC0") Signed-off-by: Stephen Boyd --- drivers/clk/st/clkgen-fsyn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/st/clkgen-fsyn.c b/drivers/clk/st/clkgen-fsyn.c index 99c98c15d4a4..d9eb2e1d8471 100644 --- a/drivers/clk/st/clkgen-fsyn.c +++ b/drivers/clk/st/clkgen-fsyn.c @@ -340,7 +340,7 @@ static const struct clkgen_quadfs_data st_fs660c32_C_407 = { CLKGEN_FIELD(0x30c, 0xf, 20), CLKGEN_FIELD(0x310, 0xf, 20) }, .lockstatus_present = true, - .lock_status = CLKGEN_FIELD(0x2A0, 0x1, 24), + .lock_status = CLKGEN_FIELD(0x2f0, 0x1, 24), .powerup_polarity = 1, .standby_polarity = 1, .pll_ops = &st_quadfs_pll_c32_ops, -- cgit v1.2.3-70-g09d2 From 5caaf5346892d1e7f0b8b7223062644f8538483f Mon Sep 17 00:00:00 2001 From: Ian Munsie Date: Tue, 7 Jul 2015 15:45:46 +1000 Subject: cxl: Fail mmap if requested mapping is larger than assigned problem state area This patch makes the mmap call fail outright if the requested region is larger than the problem state area assigned to the context so the error is reported immediately rather than waiting for an attempt to access an address out of bounds. Although we never expect users to map more than the assigned problem state area and are not aware of anyone doing this (other than for testing), this does have the potential to break users if someone has used a larger range regardless. I'm submitting it for consideration, but if this change is not considered acceptable the previous patch is sufficient to prevent access out of bounds without breaking anyone. Signed-off-by: Ian Munsie Signed-off-by: Michael Ellerman --- drivers/misc/cxl/context.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/misc/cxl/context.c b/drivers/misc/cxl/context.c index 2a4c80ac322a..6236d4a1f7ad 100644 --- a/drivers/misc/cxl/context.c +++ b/drivers/misc/cxl/context.c @@ -145,8 +145,16 @@ static const struct vm_operations_struct cxl_mmap_vmops = { */ int cxl_context_iomap(struct cxl_context *ctx, struct vm_area_struct *vma) { + u64 start = vma->vm_pgoff << PAGE_SHIFT; u64 len = vma->vm_end - vma->vm_start; - len = min(len, ctx->psn_size); + + if (ctx->afu->current_mode == CXL_MODE_DEDICATED) { + if (start + len > ctx->afu->adapter->ps_size) + return -EINVAL; + } else { + if (start + len > ctx->psn_size) + return -EINVAL; + } if (ctx->afu->current_mode != CXL_MODE_DEDICATED) { /* make sure there is a valid per process space for this AFU */ -- cgit v1.2.3-70-g09d2 From 10a5894f2dedd8a26b3132497445b314c0d952c4 Mon Sep 17 00:00:00 2001 From: Ian Munsie Date: Tue, 7 Jul 2015 15:45:45 +1000 Subject: cxl: Fix off by one error allowing subsequent mmap page to be accessed It was discovered that if a process mmaped their problem state area they were able to access one page more than expected, potentially allowing them to access the problem state area of an unrelated process. This was due to a simple off by one error in the mmap fault handler introduced in 0712dc7e73e59d79bcead5d5520acf4e9e917e87 ("cxl: Fix issues when unmapping contexts"), which is fixed in this patch. Cc: stable@vger.kernel.org Fixes: 0712dc7e73e5 ("cxl: Fix issues when unmapping contexts") Signed-off-by: Ian Munsie Signed-off-by: Michael Ellerman --- drivers/misc/cxl/context.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/cxl/context.c b/drivers/misc/cxl/context.c index 6236d4a1f7ad..1287148629c0 100644 --- a/drivers/misc/cxl/context.c +++ b/drivers/misc/cxl/context.c @@ -113,11 +113,11 @@ static int cxl_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) if (ctx->afu->current_mode == CXL_MODE_DEDICATED) { area = ctx->afu->psn_phys; - if (offset > ctx->afu->adapter->ps_size) + if (offset >= ctx->afu->adapter->ps_size) return VM_FAULT_SIGBUS; } else { area = ctx->psn_phys; - if (offset > ctx->psn_size) + if (offset >= ctx->psn_size) return VM_FAULT_SIGBUS; } -- cgit v1.2.3-70-g09d2 From 030f4e968741d65aea9cd5f7814d1164967801ef Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 7 Jul 2015 17:30:25 +0800 Subject: crypto: nx - Fix reentrancy bugs This patch fixes a host of reentrancy bugs in the nx driver. The following algorithms are affected: * CCM * GCM * CTR * XCBC * SHA256 * SHA512 The crypto API allows a single transform to be used by multiple threads simultaneously. For example, IPsec will use a single tfm to process packets for a given SA. As packets may arrive on multiple CPUs that tfm must be reentrant. The nx driver does try to deal with this by using a spin lock. Unfortunately only the basic AES/CBC/ECB algorithms do this in the correct way. The symptom of these bugs may range from the generation of incorrect output to memory corruption. Cc: stable@vger.kernel.org Signed-off-by: Herbert Xu --- drivers/crypto/nx/nx-aes-ccm.c | 6 ++-- drivers/crypto/nx/nx-aes-ctr.c | 7 +++-- drivers/crypto/nx/nx-aes-gcm.c | 17 +++++----- drivers/crypto/nx/nx-aes-xcbc.c | 70 ++++++++++++++++++++++++++--------------- drivers/crypto/nx/nx-sha256.c | 43 ++++++++++++++----------- drivers/crypto/nx/nx-sha512.c | 44 +++++++++++++++----------- drivers/crypto/nx/nx.c | 3 ++ drivers/crypto/nx/nx.h | 14 +++++++-- 8 files changed, 125 insertions(+), 79 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/nx/nx-aes-ccm.c b/drivers/crypto/nx/nx-aes-ccm.c index 67f80813a06f..e4311ce0cd78 100644 --- a/drivers/crypto/nx/nx-aes-ccm.c +++ b/drivers/crypto/nx/nx-aes-ccm.c @@ -494,8 +494,9 @@ out: static int ccm4309_aes_nx_encrypt(struct aead_request *req) { struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm); + struct nx_gcm_rctx *rctx = aead_request_ctx(req); struct blkcipher_desc desc; - u8 *iv = nx_ctx->priv.ccm.iv; + u8 *iv = rctx->iv; iv[0] = 3; memcpy(iv + 1, nx_ctx->priv.ccm.nonce, 3); @@ -525,8 +526,9 @@ static int ccm_aes_nx_encrypt(struct aead_request *req) static int ccm4309_aes_nx_decrypt(struct aead_request *req) { struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm); + struct nx_gcm_rctx *rctx = aead_request_ctx(req); struct blkcipher_desc desc; - u8 *iv = nx_ctx->priv.ccm.iv; + u8 *iv = rctx->iv; iv[0] = 3; memcpy(iv + 1, nx_ctx->priv.ccm.nonce, 3); diff --git a/drivers/crypto/nx/nx-aes-ctr.c b/drivers/crypto/nx/nx-aes-ctr.c index 2617cd4d54dd..dd7e9f3f5b6b 100644 --- a/drivers/crypto/nx/nx-aes-ctr.c +++ b/drivers/crypto/nx/nx-aes-ctr.c @@ -72,7 +72,7 @@ static int ctr3686_aes_nx_set_key(struct crypto_tfm *tfm, if (key_len < CTR_RFC3686_NONCE_SIZE) return -EINVAL; - memcpy(nx_ctx->priv.ctr.iv, + memcpy(nx_ctx->priv.ctr.nonce, in_key + key_len - CTR_RFC3686_NONCE_SIZE, CTR_RFC3686_NONCE_SIZE); @@ -131,14 +131,15 @@ static int ctr3686_aes_nx_crypt(struct blkcipher_desc *desc, unsigned int nbytes) { struct nx_crypto_ctx *nx_ctx = crypto_blkcipher_ctx(desc->tfm); - u8 *iv = nx_ctx->priv.ctr.iv; + u8 iv[16]; + memcpy(iv, nx_ctx->priv.ctr.nonce, CTR_RFC3686_IV_SIZE); memcpy(iv + CTR_RFC3686_NONCE_SIZE, desc->info, CTR_RFC3686_IV_SIZE); iv[12] = iv[13] = iv[14] = 0; iv[15] = 1; - desc->info = nx_ctx->priv.ctr.iv; + desc->info = iv; return ctr_aes_nx_crypt(desc, dst, src, nbytes); } diff --git a/drivers/crypto/nx/nx-aes-gcm.c b/drivers/crypto/nx/nx-aes-gcm.c index 08ac6d48688c..92c993f08213 100644 --- a/drivers/crypto/nx/nx-aes-gcm.c +++ b/drivers/crypto/nx/nx-aes-gcm.c @@ -317,6 +317,7 @@ out: static int gcm_aes_nx_crypt(struct aead_request *req, int enc) { struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm); + struct nx_gcm_rctx *rctx = aead_request_ctx(req); struct nx_csbcpb *csbcpb = nx_ctx->csbcpb; struct blkcipher_desc desc; unsigned int nbytes = req->cryptlen; @@ -326,7 +327,7 @@ static int gcm_aes_nx_crypt(struct aead_request *req, int enc) spin_lock_irqsave(&nx_ctx->lock, irq_flags); - desc.info = nx_ctx->priv.gcm.iv; + desc.info = rctx->iv; /* initialize the counter */ *(u32 *)(desc.info + NX_GCM_CTR_OFFSET) = 1; @@ -424,8 +425,8 @@ out: static int gcm_aes_nx_encrypt(struct aead_request *req) { - struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm); - char *iv = nx_ctx->priv.gcm.iv; + struct nx_gcm_rctx *rctx = aead_request_ctx(req); + char *iv = rctx->iv; memcpy(iv, req->iv, 12); @@ -434,8 +435,8 @@ static int gcm_aes_nx_encrypt(struct aead_request *req) static int gcm_aes_nx_decrypt(struct aead_request *req) { - struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm); - char *iv = nx_ctx->priv.gcm.iv; + struct nx_gcm_rctx *rctx = aead_request_ctx(req); + char *iv = rctx->iv; memcpy(iv, req->iv, 12); @@ -445,7 +446,8 @@ static int gcm_aes_nx_decrypt(struct aead_request *req) static int gcm4106_aes_nx_encrypt(struct aead_request *req) { struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm); - char *iv = nx_ctx->priv.gcm.iv; + struct nx_gcm_rctx *rctx = aead_request_ctx(req); + char *iv = rctx->iv; char *nonce = nx_ctx->priv.gcm.nonce; memcpy(iv, nonce, NX_GCM4106_NONCE_LEN); @@ -457,7 +459,8 @@ static int gcm4106_aes_nx_encrypt(struct aead_request *req) static int gcm4106_aes_nx_decrypt(struct aead_request *req) { struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm); - char *iv = nx_ctx->priv.gcm.iv; + struct nx_gcm_rctx *rctx = aead_request_ctx(req); + char *iv = rctx->iv; char *nonce = nx_ctx->priv.gcm.nonce; memcpy(iv, nonce, NX_GCM4106_NONCE_LEN); diff --git a/drivers/crypto/nx/nx-aes-xcbc.c b/drivers/crypto/nx/nx-aes-xcbc.c index 8c2faffab4a3..c2f7d4befb55 100644 --- a/drivers/crypto/nx/nx-aes-xcbc.c +++ b/drivers/crypto/nx/nx-aes-xcbc.c @@ -42,6 +42,7 @@ static int nx_xcbc_set_key(struct crypto_shash *desc, unsigned int key_len) { struct nx_crypto_ctx *nx_ctx = crypto_shash_ctx(desc); + struct nx_csbcpb *csbcpb = nx_ctx->csbcpb; switch (key_len) { case AES_KEYSIZE_128: @@ -51,7 +52,7 @@ static int nx_xcbc_set_key(struct crypto_shash *desc, return -EINVAL; } - memcpy(nx_ctx->priv.xcbc.key, in_key, key_len); + memcpy(csbcpb->cpb.aes_xcbc.key, in_key, key_len); return 0; } @@ -148,32 +149,29 @@ out: return rc; } -static int nx_xcbc_init(struct shash_desc *desc) +static int nx_crypto_ctx_aes_xcbc_init2(struct crypto_tfm *tfm) { - struct xcbc_state *sctx = shash_desc_ctx(desc); - struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base); + struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(tfm); struct nx_csbcpb *csbcpb = nx_ctx->csbcpb; - struct nx_sg *out_sg; - int len; + int err; - nx_ctx_init(nx_ctx, HCOP_FC_AES); + err = nx_crypto_ctx_aes_xcbc_init(tfm); + if (err) + return err; - memset(sctx, 0, sizeof *sctx); + nx_ctx_init(nx_ctx, HCOP_FC_AES); NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_128); csbcpb->cpb.hdr.mode = NX_MODE_AES_XCBC_MAC; - memcpy(csbcpb->cpb.aes_xcbc.key, nx_ctx->priv.xcbc.key, AES_BLOCK_SIZE); - memset(nx_ctx->priv.xcbc.key, 0, sizeof *nx_ctx->priv.xcbc.key); - - len = AES_BLOCK_SIZE; - out_sg = nx_build_sg_list(nx_ctx->out_sg, (u8 *)sctx->state, - &len, nx_ctx->ap->sglen); + return 0; +} - if (len != AES_BLOCK_SIZE) - return -EINVAL; +static int nx_xcbc_init(struct shash_desc *desc) +{ + struct xcbc_state *sctx = shash_desc_ctx(desc); - nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg); + memset(sctx, 0, sizeof *sctx); return 0; } @@ -186,6 +184,7 @@ static int nx_xcbc_update(struct shash_desc *desc, struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base); struct nx_csbcpb *csbcpb = nx_ctx->csbcpb; struct nx_sg *in_sg; + struct nx_sg *out_sg; u32 to_process = 0, leftover, total; unsigned int max_sg_len; unsigned long irq_flags; @@ -213,6 +212,17 @@ static int nx_xcbc_update(struct shash_desc *desc, max_sg_len = min_t(u64, max_sg_len, nx_ctx->ap->databytelen/NX_PAGE_SIZE); + data_len = AES_BLOCK_SIZE; + out_sg = nx_build_sg_list(nx_ctx->out_sg, (u8 *)sctx->state, + &len, nx_ctx->ap->sglen); + + if (data_len != AES_BLOCK_SIZE) { + rc = -EINVAL; + goto out; + } + + nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg); + do { to_process = total - to_process; to_process = to_process & ~(AES_BLOCK_SIZE - 1); @@ -235,8 +245,10 @@ static int nx_xcbc_update(struct shash_desc *desc, (u8 *) sctx->buffer, &data_len, max_sg_len); - if (data_len != sctx->count) - return -EINVAL; + if (data_len != sctx->count) { + rc = -EINVAL; + goto out; + } } data_len = to_process - sctx->count; @@ -245,8 +257,10 @@ static int nx_xcbc_update(struct shash_desc *desc, &data_len, max_sg_len); - if (data_len != to_process - sctx->count) - return -EINVAL; + if (data_len != to_process - sctx->count) { + rc = -EINVAL; + goto out; + } nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) * sizeof(struct nx_sg); @@ -325,15 +339,19 @@ static int nx_xcbc_final(struct shash_desc *desc, u8 *out) in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *)sctx->buffer, &len, nx_ctx->ap->sglen); - if (len != sctx->count) - return -EINVAL; + if (len != sctx->count) { + rc = -EINVAL; + goto out; + } len = AES_BLOCK_SIZE; out_sg = nx_build_sg_list(nx_ctx->out_sg, out, &len, nx_ctx->ap->sglen); - if (len != AES_BLOCK_SIZE) - return -EINVAL; + if (len != AES_BLOCK_SIZE) { + rc = -EINVAL; + goto out; + } nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) * sizeof(struct nx_sg); nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg); @@ -372,7 +390,7 @@ struct shash_alg nx_shash_aes_xcbc_alg = { .cra_blocksize = AES_BLOCK_SIZE, .cra_module = THIS_MODULE, .cra_ctxsize = sizeof(struct nx_crypto_ctx), - .cra_init = nx_crypto_ctx_aes_xcbc_init, + .cra_init = nx_crypto_ctx_aes_xcbc_init2, .cra_exit = nx_crypto_ctx_exit, } }; diff --git a/drivers/crypto/nx/nx-sha256.c b/drivers/crypto/nx/nx-sha256.c index 4e91bdb83c59..08f8d5cd6334 100644 --- a/drivers/crypto/nx/nx-sha256.c +++ b/drivers/crypto/nx/nx-sha256.c @@ -29,34 +29,28 @@ #include "nx.h" -static int nx_sha256_init(struct shash_desc *desc) +static int nx_crypto_ctx_sha256_init(struct crypto_tfm *tfm) { - struct sha256_state *sctx = shash_desc_ctx(desc); - struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base); - struct nx_sg *out_sg; - int len; - u32 max_sg_len; + struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(tfm); + int err; - nx_ctx_init(nx_ctx, HCOP_FC_SHA); + err = nx_crypto_ctx_sha_init(tfm); + if (err) + return err; - memset(sctx, 0, sizeof *sctx); + nx_ctx_init(nx_ctx, HCOP_FC_SHA); nx_ctx->ap = &nx_ctx->props[NX_PROPS_SHA256]; NX_CPB_SET_DIGEST_SIZE(nx_ctx->csbcpb, NX_DS_SHA256); - max_sg_len = min_t(u64, nx_ctx->ap->sglen, - nx_driver.of.max_sg_len/sizeof(struct nx_sg)); - max_sg_len = min_t(u64, max_sg_len, - nx_ctx->ap->databytelen/NX_PAGE_SIZE); + return 0; +} - len = SHA256_DIGEST_SIZE; - out_sg = nx_build_sg_list(nx_ctx->out_sg, (u8 *)sctx->state, - &len, max_sg_len); - nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg); +static int nx_sha256_init(struct shash_desc *desc) { + struct sha256_state *sctx = shash_desc_ctx(desc); - if (len != SHA256_DIGEST_SIZE) - return -EINVAL; + memset(sctx, 0, sizeof *sctx); sctx->state[0] = __cpu_to_be32(SHA256_H0); sctx->state[1] = __cpu_to_be32(SHA256_H1); @@ -78,6 +72,7 @@ static int nx_sha256_update(struct shash_desc *desc, const u8 *data, struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base); struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb; struct nx_sg *in_sg; + struct nx_sg *out_sg; u64 to_process = 0, leftover, total; unsigned long irq_flags; int rc = 0; @@ -108,6 +103,16 @@ static int nx_sha256_update(struct shash_desc *desc, const u8 *data, max_sg_len = min_t(u64, max_sg_len, nx_ctx->ap->databytelen/NX_PAGE_SIZE); + data_len = SHA256_DIGEST_SIZE; + out_sg = nx_build_sg_list(nx_ctx->out_sg, (u8 *)sctx->state, + &data_len, max_sg_len); + nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg); + + if (data_len != SHA256_DIGEST_SIZE) { + rc = -EINVAL; + goto out; + } + do { /* * to_process: the SHA256_BLOCK_SIZE data chunk to process in @@ -282,7 +287,7 @@ struct shash_alg nx_shash_sha256_alg = { .cra_blocksize = SHA256_BLOCK_SIZE, .cra_module = THIS_MODULE, .cra_ctxsize = sizeof(struct nx_crypto_ctx), - .cra_init = nx_crypto_ctx_sha_init, + .cra_init = nx_crypto_ctx_sha256_init, .cra_exit = nx_crypto_ctx_exit, } }; diff --git a/drivers/crypto/nx/nx-sha512.c b/drivers/crypto/nx/nx-sha512.c index e6a58d2ee628..aff0fe58eac0 100644 --- a/drivers/crypto/nx/nx-sha512.c +++ b/drivers/crypto/nx/nx-sha512.c @@ -28,34 +28,29 @@ #include "nx.h" -static int nx_sha512_init(struct shash_desc *desc) +static int nx_crypto_ctx_sha512_init(struct crypto_tfm *tfm) { - struct sha512_state *sctx = shash_desc_ctx(desc); - struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base); - struct nx_sg *out_sg; - int len; - u32 max_sg_len; + struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(tfm); + int err; - nx_ctx_init(nx_ctx, HCOP_FC_SHA); + err = nx_crypto_ctx_sha_init(tfm); + if (err) + return err; - memset(sctx, 0, sizeof *sctx); + nx_ctx_init(nx_ctx, HCOP_FC_SHA); nx_ctx->ap = &nx_ctx->props[NX_PROPS_SHA512]; NX_CPB_SET_DIGEST_SIZE(nx_ctx->csbcpb, NX_DS_SHA512); - max_sg_len = min_t(u64, nx_ctx->ap->sglen, - nx_driver.of.max_sg_len/sizeof(struct nx_sg)); - max_sg_len = min_t(u64, max_sg_len, - nx_ctx->ap->databytelen/NX_PAGE_SIZE); + return 0; +} - len = SHA512_DIGEST_SIZE; - out_sg = nx_build_sg_list(nx_ctx->out_sg, (u8 *)sctx->state, - &len, max_sg_len); - nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg); +static int nx_sha512_init(struct shash_desc *desc) +{ + struct sha512_state *sctx = shash_desc_ctx(desc); - if (len != SHA512_DIGEST_SIZE) - return -EINVAL; + memset(sctx, 0, sizeof *sctx); sctx->state[0] = __cpu_to_be64(SHA512_H0); sctx->state[1] = __cpu_to_be64(SHA512_H1); @@ -77,6 +72,7 @@ static int nx_sha512_update(struct shash_desc *desc, const u8 *data, struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base); struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb; struct nx_sg *in_sg; + struct nx_sg *out_sg; u64 to_process, leftover = 0, total; unsigned long irq_flags; int rc = 0; @@ -107,6 +103,16 @@ static int nx_sha512_update(struct shash_desc *desc, const u8 *data, max_sg_len = min_t(u64, max_sg_len, nx_ctx->ap->databytelen/NX_PAGE_SIZE); + data_len = SHA512_DIGEST_SIZE; + out_sg = nx_build_sg_list(nx_ctx->out_sg, (u8 *)sctx->state, + &data_len, max_sg_len); + nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg); + + if (data_len != SHA512_DIGEST_SIZE) { + rc = -EINVAL; + goto out; + } + do { /* * to_process: the SHA512_BLOCK_SIZE data chunk to process in @@ -288,7 +294,7 @@ struct shash_alg nx_shash_sha512_alg = { .cra_blocksize = SHA512_BLOCK_SIZE, .cra_module = THIS_MODULE, .cra_ctxsize = sizeof(struct nx_crypto_ctx), - .cra_init = nx_crypto_ctx_sha_init, + .cra_init = nx_crypto_ctx_sha512_init, .cra_exit = nx_crypto_ctx_exit, } }; diff --git a/drivers/crypto/nx/nx.c b/drivers/crypto/nx/nx.c index f6198f29a4a8..436971343ff7 100644 --- a/drivers/crypto/nx/nx.c +++ b/drivers/crypto/nx/nx.c @@ -713,12 +713,15 @@ static int nx_crypto_ctx_init(struct nx_crypto_ctx *nx_ctx, u32 fc, u32 mode) /* entry points from the crypto tfm initializers */ int nx_crypto_ctx_aes_ccm_init(struct crypto_tfm *tfm) { + crypto_aead_set_reqsize(__crypto_aead_cast(tfm), + sizeof(struct nx_ccm_rctx)); return nx_crypto_ctx_init(crypto_tfm_ctx(tfm), NX_FC_AES, NX_MODE_AES_CCM); } int nx_crypto_ctx_aes_gcm_init(struct crypto_aead *tfm) { + crypto_aead_set_reqsize(tfm, sizeof(struct nx_gcm_rctx)); return nx_crypto_ctx_init(crypto_aead_ctx(tfm), NX_FC_AES, NX_MODE_AES_GCM); } diff --git a/drivers/crypto/nx/nx.h b/drivers/crypto/nx/nx.h index de3ea8738146..cdff03a42ae7 100644 --- a/drivers/crypto/nx/nx.h +++ b/drivers/crypto/nx/nx.h @@ -2,6 +2,8 @@ #ifndef __NX_H__ #define __NX_H__ +#include + #define NX_NAME "nx-crypto" #define NX_STRING "IBM Power7+ Nest Accelerator Crypto Driver" #define NX_VERSION "1.0" @@ -91,8 +93,11 @@ struct nx_crypto_driver { #define NX_GCM4106_NONCE_LEN (4) #define NX_GCM_CTR_OFFSET (12) -struct nx_gcm_priv { +struct nx_gcm_rctx { u8 iv[16]; +}; + +struct nx_gcm_priv { u8 iauth_tag[16]; u8 nonce[NX_GCM4106_NONCE_LEN]; }; @@ -100,8 +105,11 @@ struct nx_gcm_priv { #define NX_CCM_AES_KEY_LEN (16) #define NX_CCM4309_AES_KEY_LEN (19) #define NX_CCM4309_NONCE_LEN (3) -struct nx_ccm_priv { +struct nx_ccm_rctx { u8 iv[16]; +}; + +struct nx_ccm_priv { u8 b0[16]; u8 iauth_tag[16]; u8 oauth_tag[16]; @@ -113,7 +121,7 @@ struct nx_xcbc_priv { }; struct nx_ctr_priv { - u8 iv[16]; + u8 nonce[CTR_RFC3686_NONCE_SIZE]; }; struct nx_crypto_ctx { -- cgit v1.2.3-70-g09d2 From 2c3d99845eb7b1e9f3d2863099bc5a25c8461d3f Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Mon, 6 Jul 2015 15:15:01 +0100 Subject: drm/i915: Restore all GGTT VMAs on resume When rotated and partial views were added no one spotted the resume path which assumes only one GGTT VMA per object and hence is now skipping rebind of alternative views. Signed-off-by: Tvrtko Ursulin Cc: Daniel Vetter Cc: Chris Wilson Cc: Joonas Lahtinen Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 9daa2883ac18..dcc6a88c560e 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -2546,6 +2546,8 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj; struct i915_address_space *vm; + struct i915_vma *vma; + bool flush; i915_check_and_clear_faults(dev); @@ -2555,16 +2557,23 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev) dev_priv->gtt.base.total, true); + /* Cache flush objects bound into GGTT and rebind them. */ + vm = &dev_priv->gtt.base; list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) { - struct i915_vma *vma = i915_gem_obj_to_vma(obj, - &dev_priv->gtt.base); - if (!vma) - continue; + flush = false; + list_for_each_entry(vma, &obj->vma_list, vma_link) { + if (vma->vm != vm) + continue; - i915_gem_clflush_object(obj, obj->pin_display); - WARN_ON(i915_vma_bind(vma, obj->cache_level, PIN_UPDATE)); - } + WARN_ON(i915_vma_bind(vma, obj->cache_level, + PIN_UPDATE)); + flush = true; + } + + if (flush) + i915_gem_clflush_object(obj, obj->pin_display); + } if (INTEL_INFO(dev)->gen >= 8) { if (IS_CHERRYVIEW(dev) || IS_BROXTON(dev)) -- cgit v1.2.3-70-g09d2 From 63fef06ada94172d7b4295fc205441bafd8f8fb3 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 7 Jul 2015 11:15:46 +0200 Subject: drm/i915: Check crtc->active in intel_crtc_disable_planes This was lost in commit ce22dba92de22e951dee2ff89937a39754d2dd91 Author: Maarten Lankhorst Date: Tue Apr 21 17:12:56 2015 +0300 drm/i915: Move toggling planes out of crtc enable/disable. and we still need that crtc->active check since the overall modeset flow doesn't yet take dpms state into account properly. Fixes WARNING backtraces on at least bdw/hsw due to the ips disabling code being upset about being run on a switched-off pipe. We don't need a corresponding change on the enable side since with the old setCrtc semantics we always force-enable the pipe after a modeset. And the dpms function intel_crtc_control already checks for ->active. Reported-by: Linus Torvalds Cc: Linus Torvalds Cc: Maarten Lankhorst Cc: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8aa803848f35..647b1404c441 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4854,6 +4854,9 @@ static void intel_crtc_disable_planes(struct drm_crtc *crtc) struct intel_plane *intel_plane; int pipe = intel_crtc->pipe; + if (!intel_crtc->active) + return; + intel_crtc_wait_for_pending_flips(crtc); intel_pre_disable_primary(crtc); -- cgit v1.2.3-70-g09d2 From dec4f799d0a4c9edae20512fa60b0a36f3299ca2 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 7 Jul 2015 11:15:47 +0200 Subject: drm/i915: Use crtc_state->active in primary check_plane func Since commit 8c7b5ccb729870e606321b3703e2c2e698c49a95 Author: Ander Conselvan de Oliveira Date: Tue Apr 21 17:13:19 2015 +0300 drm/i915: Use atomic helpers for computing changed flags we compute the plane state for a modeset before actually committing any changes, which means crtc->active won't be correct yet. Looking at future work in the modeset conversion targetting 4.3 the only places where crtc_state->active isn't accurate is when disabling other CRTCs than the one the modeset is for (when stealing connectors). Which isn't the case here. And that's also confirmed by an audit, we do unconditionally update crtc_state->active for the current pipe. We also don't need to update any other plane check functions since we only ever add the primary state to the modeset update right now. Cc: Ander Conselvan de Oliveira Cc: Maarten Lankhorst Cc: Jani Nikula Signed-off-by: Daniel Vetter Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 647b1404c441..ba9321998a41 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13276,7 +13276,7 @@ intel_check_primary_plane(struct drm_plane *plane, if (ret) return ret; - if (intel_crtc->active) { + if (crtc_state->base.active) { struct intel_plane_state *old_state = to_intel_plane_state(plane->state); -- cgit v1.2.3-70-g09d2 From 07f18f0bb8d8d65badd8b4988b40d329fc0cc6dc Mon Sep 17 00:00:00 2001 From: Mario Kleiner Date: Fri, 3 Jul 2015 06:03:06 +0200 Subject: drm/radeon: Handle irqs only based on irq ring, not irq status regs. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Trying to resolve issues with missed vblanks and impossible values inside delivered kms pageflip completion events showed that radeon's irq handling sometimes doesn't handle valid irqs, but silently skips them. This was observed for vblank interrupts. Although those irqs have corresponding events queued in the gpu's irq ring at time of interrupt, and therefore the corresponding handling code gets triggered by these events, the handling code sometimes silently skipped processing the irq. The reason for those skips is that the handling code double-checks for each irq event if the corresponding irq status bits in the irq status registers are set. Sometimes those bits are not set at time of check for valid irqs, maybe due to some hardware race on some setups? The problem only seems to happen on some machine + card combos sometimes, e.g., never happened during my testing of different PC cards of the DCE-2/3/4 generation a year ago, but happens consistently now on two different Apple Mac cards (RV730, DCE-3, Apple iMac and Evergreen JUNIPER, DCE-4 in a Apple MacPro). It also doesn't happen at each interrupt but only occassionally every couple of hundred or thousand vblank interrupts. This results in XOrg warning messages like "[ 7084.472] (WW) RADEON(0): radeon_dri2_flip_event_handler: Pageflip completion event has impossible msc 420120 < target_msc 420121" as well as skipped frames and problems for applications that use kms pageflip events or vblank events, e.g., users of DRI2 and DRI3/Present, Waylands Weston compositor, etc. See also https://bugs.freedesktop.org/show_bug.cgi?id=85203 After some talking to Alex and Michel, we decided to fix this by turning the double-check for asserted irq status bits into a warning. Whenever a irq event is queued in the IH ring, always execute the corresponding interrupt handler. Still check the irq status bits, but only to log a DRM_DEBUG message on a mismatch. This fixed the problems reliably on both previously failing cards, RV-730 dual-head tested on both crtcs (pipes D1 and D2) and a triple-output Juniper HD-5770 card tested on all three available crtcs (D1/D2/D3). The r600 and evergreen irq handling is therefore tested, but the cik an si handling is only compile tested due to lack of hw. Reviewed-by: Christian König Signed-off-by: Mario Kleiner CC: Michel Dänzer CC: Alex Deucher CC: # v3.16+ Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/cik.c | 336 +++++++++++++++++-------------- drivers/gpu/drm/radeon/evergreen.c | 392 ++++++++++++++++++++----------------- drivers/gpu/drm/radeon/r600.c | 155 ++++++++------- drivers/gpu/drm/radeon/si.c | 336 +++++++++++++++++-------------- 4 files changed, 688 insertions(+), 531 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index 4ecf5caa8c6d..248953d2fdb7 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -7964,23 +7964,27 @@ restart_ih: case 1: /* D1 vblank/vline */ switch (src_data) { case 0: /* D1 vblank */ - if (rdev->irq.stat_regs.cik.disp_int & LB_D1_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[0]) { - drm_handle_vblank(rdev->ddev, 0); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[0])) - radeon_crtc_handle_vblank(rdev, 0); - rdev->irq.stat_regs.cik.disp_int &= ~LB_D1_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D1 vblank\n"); + if (!(rdev->irq.stat_regs.cik.disp_int & LB_D1_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[0]) { + drm_handle_vblank(rdev->ddev, 0); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[0])) + radeon_crtc_handle_vblank(rdev, 0); + rdev->irq.stat_regs.cik.disp_int &= ~LB_D1_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D1 vblank\n"); + break; case 1: /* D1 vline */ - if (rdev->irq.stat_regs.cik.disp_int & LB_D1_VLINE_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int &= ~LB_D1_VLINE_INTERRUPT; - DRM_DEBUG("IH: D1 vline\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int & LB_D1_VLINE_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int &= ~LB_D1_VLINE_INTERRUPT; + DRM_DEBUG("IH: D1 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -7990,23 +7994,27 @@ restart_ih: case 2: /* D2 vblank/vline */ switch (src_data) { case 0: /* D2 vblank */ - if (rdev->irq.stat_regs.cik.disp_int_cont & LB_D2_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[1]) { - drm_handle_vblank(rdev->ddev, 1); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[1])) - radeon_crtc_handle_vblank(rdev, 1); - rdev->irq.stat_regs.cik.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D2 vblank\n"); + if (!(rdev->irq.stat_regs.cik.disp_int_cont & LB_D2_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[1]) { + drm_handle_vblank(rdev->ddev, 1); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[1])) + radeon_crtc_handle_vblank(rdev, 1); + rdev->irq.stat_regs.cik.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D2 vblank\n"); + break; case 1: /* D2 vline */ - if (rdev->irq.stat_regs.cik.disp_int_cont & LB_D2_VLINE_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int_cont &= ~LB_D2_VLINE_INTERRUPT; - DRM_DEBUG("IH: D2 vline\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont & LB_D2_VLINE_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont &= ~LB_D2_VLINE_INTERRUPT; + DRM_DEBUG("IH: D2 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -8016,23 +8024,27 @@ restart_ih: case 3: /* D3 vblank/vline */ switch (src_data) { case 0: /* D3 vblank */ - if (rdev->irq.stat_regs.cik.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[2]) { - drm_handle_vblank(rdev->ddev, 2); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[2])) - radeon_crtc_handle_vblank(rdev, 2); - rdev->irq.stat_regs.cik.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D3 vblank\n"); + if (!(rdev->irq.stat_regs.cik.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[2]) { + drm_handle_vblank(rdev->ddev, 2); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[2])) + radeon_crtc_handle_vblank(rdev, 2); + rdev->irq.stat_regs.cik.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D3 vblank\n"); + break; case 1: /* D3 vline */ - if (rdev->irq.stat_regs.cik.disp_int_cont2 & LB_D3_VLINE_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int_cont2 &= ~LB_D3_VLINE_INTERRUPT; - DRM_DEBUG("IH: D3 vline\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont2 & LB_D3_VLINE_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont2 &= ~LB_D3_VLINE_INTERRUPT; + DRM_DEBUG("IH: D3 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -8042,23 +8054,27 @@ restart_ih: case 4: /* D4 vblank/vline */ switch (src_data) { case 0: /* D4 vblank */ - if (rdev->irq.stat_regs.cik.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[3]) { - drm_handle_vblank(rdev->ddev, 3); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[3])) - radeon_crtc_handle_vblank(rdev, 3); - rdev->irq.stat_regs.cik.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D4 vblank\n"); + if (!(rdev->irq.stat_regs.cik.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[3]) { + drm_handle_vblank(rdev->ddev, 3); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[3])) + radeon_crtc_handle_vblank(rdev, 3); + rdev->irq.stat_regs.cik.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D4 vblank\n"); + break; case 1: /* D4 vline */ - if (rdev->irq.stat_regs.cik.disp_int_cont3 & LB_D4_VLINE_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int_cont3 &= ~LB_D4_VLINE_INTERRUPT; - DRM_DEBUG("IH: D4 vline\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont3 & LB_D4_VLINE_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont3 &= ~LB_D4_VLINE_INTERRUPT; + DRM_DEBUG("IH: D4 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -8068,23 +8084,27 @@ restart_ih: case 5: /* D5 vblank/vline */ switch (src_data) { case 0: /* D5 vblank */ - if (rdev->irq.stat_regs.cik.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[4]) { - drm_handle_vblank(rdev->ddev, 4); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[4])) - radeon_crtc_handle_vblank(rdev, 4); - rdev->irq.stat_regs.cik.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D5 vblank\n"); + if (!(rdev->irq.stat_regs.cik.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[4]) { + drm_handle_vblank(rdev->ddev, 4); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[4])) + radeon_crtc_handle_vblank(rdev, 4); + rdev->irq.stat_regs.cik.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D5 vblank\n"); + break; case 1: /* D5 vline */ - if (rdev->irq.stat_regs.cik.disp_int_cont4 & LB_D5_VLINE_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int_cont4 &= ~LB_D5_VLINE_INTERRUPT; - DRM_DEBUG("IH: D5 vline\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont4 & LB_D5_VLINE_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont4 &= ~LB_D5_VLINE_INTERRUPT; + DRM_DEBUG("IH: D5 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -8094,23 +8114,27 @@ restart_ih: case 6: /* D6 vblank/vline */ switch (src_data) { case 0: /* D6 vblank */ - if (rdev->irq.stat_regs.cik.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[5]) { - drm_handle_vblank(rdev->ddev, 5); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[5])) - radeon_crtc_handle_vblank(rdev, 5); - rdev->irq.stat_regs.cik.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D6 vblank\n"); + if (!(rdev->irq.stat_regs.cik.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[5]) { + drm_handle_vblank(rdev->ddev, 5); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[5])) + radeon_crtc_handle_vblank(rdev, 5); + rdev->irq.stat_regs.cik.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D6 vblank\n"); + break; case 1: /* D6 vline */ - if (rdev->irq.stat_regs.cik.disp_int_cont5 & LB_D6_VLINE_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int_cont5 &= ~LB_D6_VLINE_INTERRUPT; - DRM_DEBUG("IH: D6 vline\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont5 & LB_D6_VLINE_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont5 &= ~LB_D6_VLINE_INTERRUPT; + DRM_DEBUG("IH: D6 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -8130,88 +8154,112 @@ restart_ih: case 42: /* HPD hotplug */ switch (src_data) { case 0: - if (rdev->irq.stat_regs.cik.disp_int & DC_HPD1_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int &= ~DC_HPD1_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD1\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int & DC_HPD1_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int &= ~DC_HPD1_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD1\n"); + break; case 1: - if (rdev->irq.stat_regs.cik.disp_int_cont & DC_HPD2_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int_cont &= ~DC_HPD2_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD2\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont & DC_HPD2_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont &= ~DC_HPD2_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD2\n"); + break; case 2: - if (rdev->irq.stat_regs.cik.disp_int_cont2 & DC_HPD3_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int_cont2 &= ~DC_HPD3_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD3\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont2 & DC_HPD3_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont2 &= ~DC_HPD3_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD3\n"); + break; case 3: - if (rdev->irq.stat_regs.cik.disp_int_cont3 & DC_HPD4_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int_cont3 &= ~DC_HPD4_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD4\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont3 & DC_HPD4_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont3 &= ~DC_HPD4_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD4\n"); + break; case 4: - if (rdev->irq.stat_regs.cik.disp_int_cont4 & DC_HPD5_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int_cont4 &= ~DC_HPD5_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD5\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont4 & DC_HPD5_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont4 &= ~DC_HPD5_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD5\n"); + break; case 5: - if (rdev->irq.stat_regs.cik.disp_int_cont5 & DC_HPD6_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int_cont5 &= ~DC_HPD6_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD6\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont5 & DC_HPD6_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont5 &= ~DC_HPD6_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD6\n"); + break; case 6: - if (rdev->irq.stat_regs.cik.disp_int & DC_HPD1_RX_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int &= ~DC_HPD1_RX_INTERRUPT; - queue_dp = true; - DRM_DEBUG("IH: HPD_RX 1\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int & DC_HPD1_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int &= ~DC_HPD1_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 1\n"); + break; case 7: - if (rdev->irq.stat_regs.cik.disp_int_cont & DC_HPD2_RX_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int_cont &= ~DC_HPD2_RX_INTERRUPT; - queue_dp = true; - DRM_DEBUG("IH: HPD_RX 2\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont & DC_HPD2_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont &= ~DC_HPD2_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 2\n"); + break; case 8: - if (rdev->irq.stat_regs.cik.disp_int_cont2 & DC_HPD3_RX_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int_cont2 &= ~DC_HPD3_RX_INTERRUPT; - queue_dp = true; - DRM_DEBUG("IH: HPD_RX 3\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont2 & DC_HPD3_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont2 &= ~DC_HPD3_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 3\n"); + break; case 9: - if (rdev->irq.stat_regs.cik.disp_int_cont3 & DC_HPD4_RX_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int_cont3 &= ~DC_HPD4_RX_INTERRUPT; - queue_dp = true; - DRM_DEBUG("IH: HPD_RX 4\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont3 & DC_HPD4_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont3 &= ~DC_HPD4_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 4\n"); + break; case 10: - if (rdev->irq.stat_regs.cik.disp_int_cont4 & DC_HPD5_RX_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int_cont4 &= ~DC_HPD5_RX_INTERRUPT; - queue_dp = true; - DRM_DEBUG("IH: HPD_RX 5\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont4 & DC_HPD5_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont4 &= ~DC_HPD5_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 5\n"); + break; case 11: - if (rdev->irq.stat_regs.cik.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int_cont5 &= ~DC_HPD6_RX_INTERRUPT; - queue_dp = true; - DRM_DEBUG("IH: HPD_RX 6\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont5 & DC_HPD6_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont5 &= ~DC_HPD6_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 6\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 3a6d483a2c36..0acde1949c18 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -4924,7 +4924,7 @@ restart_ih: return IRQ_NONE; rptr = rdev->ih.rptr; - DRM_DEBUG("r600_irq_process start: rptr %d, wptr %d\n", rptr, wptr); + DRM_DEBUG("evergreen_irq_process start: rptr %d, wptr %d\n", rptr, wptr); /* Order reading of wptr vs. reading of IH ring data */ rmb(); @@ -4942,23 +4942,27 @@ restart_ih: case 1: /* D1 vblank/vline */ switch (src_data) { case 0: /* D1 vblank */ - if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[0]) { - drm_handle_vblank(rdev->ddev, 0); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[0])) - radeon_crtc_handle_vblank(rdev, 0); - rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D1 vblank\n"); + if (!(rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: D1 vblank - IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[0]) { + drm_handle_vblank(rdev->ddev, 0); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[0])) + radeon_crtc_handle_vblank(rdev, 0); + rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D1 vblank\n"); + break; case 1: /* D1 vline */ - if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VLINE_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VLINE_INTERRUPT; - DRM_DEBUG("IH: D1 vline\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VLINE_INTERRUPT)) + DRM_DEBUG("IH: D1 vline - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VLINE_INTERRUPT; + DRM_DEBUG("IH: D1 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -4968,23 +4972,27 @@ restart_ih: case 2: /* D2 vblank/vline */ switch (src_data) { case 0: /* D2 vblank */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[1]) { - drm_handle_vblank(rdev->ddev, 1); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[1])) - radeon_crtc_handle_vblank(rdev, 1); - rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D2 vblank\n"); + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: D2 vblank - IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[1]) { + drm_handle_vblank(rdev->ddev, 1); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[1])) + radeon_crtc_handle_vblank(rdev, 1); + rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D2 vblank\n"); + break; case 1: /* D2 vline */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VLINE_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VLINE_INTERRUPT; - DRM_DEBUG("IH: D2 vline\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VLINE_INTERRUPT)) + DRM_DEBUG("IH: D2 vline - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VLINE_INTERRUPT; + DRM_DEBUG("IH: D2 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -4994,23 +5002,27 @@ restart_ih: case 3: /* D3 vblank/vline */ switch (src_data) { case 0: /* D3 vblank */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[2]) { - drm_handle_vblank(rdev->ddev, 2); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[2])) - radeon_crtc_handle_vblank(rdev, 2); - rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D3 vblank\n"); + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: D3 vblank - IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[2]) { + drm_handle_vblank(rdev->ddev, 2); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[2])) + radeon_crtc_handle_vblank(rdev, 2); + rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D3 vblank\n"); + break; case 1: /* D3 vline */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VLINE_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VLINE_INTERRUPT; - DRM_DEBUG("IH: D3 vline\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VLINE_INTERRUPT)) + DRM_DEBUG("IH: D3 vline - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VLINE_INTERRUPT; + DRM_DEBUG("IH: D3 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -5020,23 +5032,27 @@ restart_ih: case 4: /* D4 vblank/vline */ switch (src_data) { case 0: /* D4 vblank */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[3]) { - drm_handle_vblank(rdev->ddev, 3); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[3])) - radeon_crtc_handle_vblank(rdev, 3); - rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D4 vblank\n"); + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: D4 vblank - IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[3]) { + drm_handle_vblank(rdev->ddev, 3); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[3])) + radeon_crtc_handle_vblank(rdev, 3); + rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D4 vblank\n"); + break; case 1: /* D4 vline */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VLINE_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VLINE_INTERRUPT; - DRM_DEBUG("IH: D4 vline\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VLINE_INTERRUPT)) + DRM_DEBUG("IH: D4 vline - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VLINE_INTERRUPT; + DRM_DEBUG("IH: D4 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -5046,23 +5062,27 @@ restart_ih: case 5: /* D5 vblank/vline */ switch (src_data) { case 0: /* D5 vblank */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[4]) { - drm_handle_vblank(rdev->ddev, 4); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[4])) - radeon_crtc_handle_vblank(rdev, 4); - rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D5 vblank\n"); + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: D5 vblank - IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[4]) { + drm_handle_vblank(rdev->ddev, 4); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[4])) + radeon_crtc_handle_vblank(rdev, 4); + rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D5 vblank\n"); + break; case 1: /* D5 vline */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VLINE_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VLINE_INTERRUPT; - DRM_DEBUG("IH: D5 vline\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VLINE_INTERRUPT)) + DRM_DEBUG("IH: D5 vline - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VLINE_INTERRUPT; + DRM_DEBUG("IH: D5 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -5072,23 +5092,27 @@ restart_ih: case 6: /* D6 vblank/vline */ switch (src_data) { case 0: /* D6 vblank */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[5]) { - drm_handle_vblank(rdev->ddev, 5); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[5])) - radeon_crtc_handle_vblank(rdev, 5); - rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D6 vblank\n"); + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: D6 vblank - IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[5]) { + drm_handle_vblank(rdev->ddev, 5); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[5])) + radeon_crtc_handle_vblank(rdev, 5); + rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D6 vblank\n"); + break; case 1: /* D6 vline */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VLINE_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VLINE_INTERRUPT; - DRM_DEBUG("IH: D6 vline\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VLINE_INTERRUPT)) + DRM_DEBUG("IH: D6 vline - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VLINE_INTERRUPT; + DRM_DEBUG("IH: D6 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -5108,88 +5132,100 @@ restart_ih: case 42: /* HPD hotplug */ switch (src_data) { case 0: - if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD1\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD1\n"); break; case 1: - if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD2\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD2\n"); break; case 2: - if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD3\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD3\n"); break; case 3: - if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD4\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD4\n"); break; case 4: - if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD5\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD5\n"); break; case 5: - if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD6\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD6\n"); break; case 6: - if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_RX_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_RX_INTERRUPT; - queue_dp = true; - DRM_DEBUG("IH: HPD_RX 1\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 1\n"); break; case 7: - if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_RX_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_RX_INTERRUPT; - queue_dp = true; - DRM_DEBUG("IH: HPD_RX 2\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 2\n"); break; case 8: - if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_RX_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_RX_INTERRUPT; - queue_dp = true; - DRM_DEBUG("IH: HPD_RX 3\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 3\n"); break; case 9: - if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_RX_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_RX_INTERRUPT; - queue_dp = true; - DRM_DEBUG("IH: HPD_RX 4\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 4\n"); break; case 10: - if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_RX_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_RX_INTERRUPT; - queue_dp = true; - DRM_DEBUG("IH: HPD_RX 5\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 5\n"); break; case 11: - if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_RX_INTERRUPT; - queue_dp = true; - DRM_DEBUG("IH: HPD_RX 6\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 6\n"); break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -5199,46 +5235,52 @@ restart_ih: case 44: /* hdmi */ switch (src_data) { case 0: - if (rdev->irq.stat_regs.evergreen.afmt_status1 & AFMT_AZ_FORMAT_WTRIG) { - rdev->irq.stat_regs.evergreen.afmt_status1 &= ~AFMT_AZ_FORMAT_WTRIG; - queue_hdmi = true; - DRM_DEBUG("IH: HDMI0\n"); - } + if (!(rdev->irq.stat_regs.evergreen.afmt_status1 & AFMT_AZ_FORMAT_WTRIG)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.afmt_status1 &= ~AFMT_AZ_FORMAT_WTRIG; + queue_hdmi = true; + DRM_DEBUG("IH: HDMI0\n"); break; case 1: - if (rdev->irq.stat_regs.evergreen.afmt_status2 & AFMT_AZ_FORMAT_WTRIG) { - rdev->irq.stat_regs.evergreen.afmt_status2 &= ~AFMT_AZ_FORMAT_WTRIG; - queue_hdmi = true; - DRM_DEBUG("IH: HDMI1\n"); - } + if (!(rdev->irq.stat_regs.evergreen.afmt_status2 & AFMT_AZ_FORMAT_WTRIG)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.afmt_status2 &= ~AFMT_AZ_FORMAT_WTRIG; + queue_hdmi = true; + DRM_DEBUG("IH: HDMI1\n"); break; case 2: - if (rdev->irq.stat_regs.evergreen.afmt_status3 & AFMT_AZ_FORMAT_WTRIG) { - rdev->irq.stat_regs.evergreen.afmt_status3 &= ~AFMT_AZ_FORMAT_WTRIG; - queue_hdmi = true; - DRM_DEBUG("IH: HDMI2\n"); - } + if (!(rdev->irq.stat_regs.evergreen.afmt_status3 & AFMT_AZ_FORMAT_WTRIG)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.afmt_status3 &= ~AFMT_AZ_FORMAT_WTRIG; + queue_hdmi = true; + DRM_DEBUG("IH: HDMI2\n"); break; case 3: - if (rdev->irq.stat_regs.evergreen.afmt_status4 & AFMT_AZ_FORMAT_WTRIG) { - rdev->irq.stat_regs.evergreen.afmt_status4 &= ~AFMT_AZ_FORMAT_WTRIG; - queue_hdmi = true; - DRM_DEBUG("IH: HDMI3\n"); - } + if (!(rdev->irq.stat_regs.evergreen.afmt_status4 & AFMT_AZ_FORMAT_WTRIG)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.afmt_status4 &= ~AFMT_AZ_FORMAT_WTRIG; + queue_hdmi = true; + DRM_DEBUG("IH: HDMI3\n"); break; case 4: - if (rdev->irq.stat_regs.evergreen.afmt_status5 & AFMT_AZ_FORMAT_WTRIG) { - rdev->irq.stat_regs.evergreen.afmt_status5 &= ~AFMT_AZ_FORMAT_WTRIG; - queue_hdmi = true; - DRM_DEBUG("IH: HDMI4\n"); - } + if (!(rdev->irq.stat_regs.evergreen.afmt_status5 & AFMT_AZ_FORMAT_WTRIG)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.afmt_status5 &= ~AFMT_AZ_FORMAT_WTRIG; + queue_hdmi = true; + DRM_DEBUG("IH: HDMI4\n"); break; case 5: - if (rdev->irq.stat_regs.evergreen.afmt_status6 & AFMT_AZ_FORMAT_WTRIG) { - rdev->irq.stat_regs.evergreen.afmt_status6 &= ~AFMT_AZ_FORMAT_WTRIG; - queue_hdmi = true; - DRM_DEBUG("IH: HDMI5\n"); - } + if (!(rdev->irq.stat_regs.evergreen.afmt_status6 & AFMT_AZ_FORMAT_WTRIG)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.afmt_status6 &= ~AFMT_AZ_FORMAT_WTRIG; + queue_hdmi = true; + DRM_DEBUG("IH: HDMI5\n"); break; default: DRM_ERROR("Unhandled interrupt: %d %d\n", src_id, src_data); diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 35dafd77a639..4ea5b10ff5f4 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -4086,23 +4086,27 @@ restart_ih: case 1: /* D1 vblank/vline */ switch (src_data) { case 0: /* D1 vblank */ - if (rdev->irq.stat_regs.r600.disp_int & LB_D1_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[0]) { - drm_handle_vblank(rdev->ddev, 0); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[0])) - radeon_crtc_handle_vblank(rdev, 0); - rdev->irq.stat_regs.r600.disp_int &= ~LB_D1_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D1 vblank\n"); + if (!(rdev->irq.stat_regs.r600.disp_int & LB_D1_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: D1 vblank - IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[0]) { + drm_handle_vblank(rdev->ddev, 0); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[0])) + radeon_crtc_handle_vblank(rdev, 0); + rdev->irq.stat_regs.r600.disp_int &= ~LB_D1_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D1 vblank\n"); + break; case 1: /* D1 vline */ - if (rdev->irq.stat_regs.r600.disp_int & LB_D1_VLINE_INTERRUPT) { - rdev->irq.stat_regs.r600.disp_int &= ~LB_D1_VLINE_INTERRUPT; - DRM_DEBUG("IH: D1 vline\n"); - } + if (!(rdev->irq.stat_regs.r600.disp_int & LB_D1_VLINE_INTERRUPT)) + DRM_DEBUG("IH: D1 vline - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.r600.disp_int &= ~LB_D1_VLINE_INTERRUPT; + DRM_DEBUG("IH: D1 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -4112,23 +4116,27 @@ restart_ih: case 5: /* D2 vblank/vline */ switch (src_data) { case 0: /* D2 vblank */ - if (rdev->irq.stat_regs.r600.disp_int & LB_D2_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[1]) { - drm_handle_vblank(rdev->ddev, 1); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[1])) - radeon_crtc_handle_vblank(rdev, 1); - rdev->irq.stat_regs.r600.disp_int &= ~LB_D2_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D2 vblank\n"); + if (!(rdev->irq.stat_regs.r600.disp_int & LB_D2_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: D2 vblank - IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[1]) { + drm_handle_vblank(rdev->ddev, 1); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[1])) + radeon_crtc_handle_vblank(rdev, 1); + rdev->irq.stat_regs.r600.disp_int &= ~LB_D2_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D2 vblank\n"); + break; case 1: /* D1 vline */ - if (rdev->irq.stat_regs.r600.disp_int & LB_D2_VLINE_INTERRUPT) { - rdev->irq.stat_regs.r600.disp_int &= ~LB_D2_VLINE_INTERRUPT; - DRM_DEBUG("IH: D2 vline\n"); - } + if (!(rdev->irq.stat_regs.r600.disp_int & LB_D2_VLINE_INTERRUPT)) + DRM_DEBUG("IH: D2 vline - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.r600.disp_int &= ~LB_D2_VLINE_INTERRUPT; + DRM_DEBUG("IH: D2 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -4148,46 +4156,53 @@ restart_ih: case 19: /* HPD/DAC hotplug */ switch (src_data) { case 0: - if (rdev->irq.stat_regs.r600.disp_int & DC_HPD1_INTERRUPT) { - rdev->irq.stat_regs.r600.disp_int &= ~DC_HPD1_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD1\n"); - } + if (!(rdev->irq.stat_regs.r600.disp_int & DC_HPD1_INTERRUPT)) + DRM_DEBUG("IH: HPD1 - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.r600.disp_int &= ~DC_HPD1_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD1\n"); break; case 1: - if (rdev->irq.stat_regs.r600.disp_int & DC_HPD2_INTERRUPT) { - rdev->irq.stat_regs.r600.disp_int &= ~DC_HPD2_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD2\n"); - } + if (!(rdev->irq.stat_regs.r600.disp_int & DC_HPD2_INTERRUPT)) + DRM_DEBUG("IH: HPD2 - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.r600.disp_int &= ~DC_HPD2_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD2\n"); break; case 4: - if (rdev->irq.stat_regs.r600.disp_int_cont & DC_HPD3_INTERRUPT) { - rdev->irq.stat_regs.r600.disp_int_cont &= ~DC_HPD3_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD3\n"); - } + if (!(rdev->irq.stat_regs.r600.disp_int_cont & DC_HPD3_INTERRUPT)) + DRM_DEBUG("IH: HPD3 - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.r600.disp_int_cont &= ~DC_HPD3_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD3\n"); break; case 5: - if (rdev->irq.stat_regs.r600.disp_int_cont & DC_HPD4_INTERRUPT) { - rdev->irq.stat_regs.r600.disp_int_cont &= ~DC_HPD4_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD4\n"); - } + if (!(rdev->irq.stat_regs.r600.disp_int_cont & DC_HPD4_INTERRUPT)) + DRM_DEBUG("IH: HPD4 - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.r600.disp_int_cont &= ~DC_HPD4_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD4\n"); break; case 10: - if (rdev->irq.stat_regs.r600.disp_int_cont2 & DC_HPD5_INTERRUPT) { - rdev->irq.stat_regs.r600.disp_int_cont2 &= ~DC_HPD5_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD5\n"); - } + if (!(rdev->irq.stat_regs.r600.disp_int_cont2 & DC_HPD5_INTERRUPT)) + DRM_DEBUG("IH: HPD5 - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.r600.disp_int_cont2 &= ~DC_HPD5_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD5\n"); break; case 12: - if (rdev->irq.stat_regs.r600.disp_int_cont2 & DC_HPD6_INTERRUPT) { - rdev->irq.stat_regs.r600.disp_int_cont2 &= ~DC_HPD6_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD6\n"); - } + if (!(rdev->irq.stat_regs.r600.disp_int_cont2 & DC_HPD6_INTERRUPT)) + DRM_DEBUG("IH: HPD6 - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.r600.disp_int_cont2 &= ~DC_HPD6_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD6\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -4197,18 +4212,22 @@ restart_ih: case 21: /* hdmi */ switch (src_data) { case 4: - if (rdev->irq.stat_regs.r600.hdmi0_status & HDMI0_AZ_FORMAT_WTRIG) { - rdev->irq.stat_regs.r600.hdmi0_status &= ~HDMI0_AZ_FORMAT_WTRIG; - queue_hdmi = true; - DRM_DEBUG("IH: HDMI0\n"); - } + if (!(rdev->irq.stat_regs.r600.hdmi0_status & HDMI0_AZ_FORMAT_WTRIG)) + DRM_DEBUG("IH: HDMI0 - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.r600.hdmi0_status &= ~HDMI0_AZ_FORMAT_WTRIG; + queue_hdmi = true; + DRM_DEBUG("IH: HDMI0\n"); + break; case 5: - if (rdev->irq.stat_regs.r600.hdmi1_status & HDMI0_AZ_FORMAT_WTRIG) { - rdev->irq.stat_regs.r600.hdmi1_status &= ~HDMI0_AZ_FORMAT_WTRIG; - queue_hdmi = true; - DRM_DEBUG("IH: HDMI1\n"); - } + if (!(rdev->irq.stat_regs.r600.hdmi1_status & HDMI0_AZ_FORMAT_WTRIG)) + DRM_DEBUG("IH: HDMI1 - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.r600.hdmi1_status &= ~HDMI0_AZ_FORMAT_WTRIG; + queue_hdmi = true; + DRM_DEBUG("IH: HDMI1\n"); + break; default: DRM_ERROR("Unhandled interrupt: %d %d\n", src_id, src_data); diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 26388b5dd6ed..07037e32dea3 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -6466,23 +6466,27 @@ restart_ih: case 1: /* D1 vblank/vline */ switch (src_data) { case 0: /* D1 vblank */ - if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[0]) { - drm_handle_vblank(rdev->ddev, 0); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[0])) - radeon_crtc_handle_vblank(rdev, 0); - rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D1 vblank\n"); + if (!(rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[0]) { + drm_handle_vblank(rdev->ddev, 0); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[0])) + radeon_crtc_handle_vblank(rdev, 0); + rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D1 vblank\n"); + break; case 1: /* D1 vline */ - if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VLINE_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VLINE_INTERRUPT; - DRM_DEBUG("IH: D1 vline\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VLINE_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VLINE_INTERRUPT; + DRM_DEBUG("IH: D1 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -6492,23 +6496,27 @@ restart_ih: case 2: /* D2 vblank/vline */ switch (src_data) { case 0: /* D2 vblank */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[1]) { - drm_handle_vblank(rdev->ddev, 1); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[1])) - radeon_crtc_handle_vblank(rdev, 1); - rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D2 vblank\n"); + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[1]) { + drm_handle_vblank(rdev->ddev, 1); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[1])) + radeon_crtc_handle_vblank(rdev, 1); + rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D2 vblank\n"); + break; case 1: /* D2 vline */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VLINE_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VLINE_INTERRUPT; - DRM_DEBUG("IH: D2 vline\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VLINE_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VLINE_INTERRUPT; + DRM_DEBUG("IH: D2 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -6518,23 +6526,27 @@ restart_ih: case 3: /* D3 vblank/vline */ switch (src_data) { case 0: /* D3 vblank */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[2]) { - drm_handle_vblank(rdev->ddev, 2); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[2])) - radeon_crtc_handle_vblank(rdev, 2); - rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D3 vblank\n"); + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[2]) { + drm_handle_vblank(rdev->ddev, 2); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[2])) + radeon_crtc_handle_vblank(rdev, 2); + rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D3 vblank\n"); + break; case 1: /* D3 vline */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VLINE_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VLINE_INTERRUPT; - DRM_DEBUG("IH: D3 vline\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VLINE_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VLINE_INTERRUPT; + DRM_DEBUG("IH: D3 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -6544,23 +6556,27 @@ restart_ih: case 4: /* D4 vblank/vline */ switch (src_data) { case 0: /* D4 vblank */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[3]) { - drm_handle_vblank(rdev->ddev, 3); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[3])) - radeon_crtc_handle_vblank(rdev, 3); - rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D4 vblank\n"); + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[3]) { + drm_handle_vblank(rdev->ddev, 3); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[3])) + radeon_crtc_handle_vblank(rdev, 3); + rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D4 vblank\n"); + break; case 1: /* D4 vline */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VLINE_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VLINE_INTERRUPT; - DRM_DEBUG("IH: D4 vline\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VLINE_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VLINE_INTERRUPT; + DRM_DEBUG("IH: D4 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -6570,23 +6586,27 @@ restart_ih: case 5: /* D5 vblank/vline */ switch (src_data) { case 0: /* D5 vblank */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[4]) { - drm_handle_vblank(rdev->ddev, 4); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[4])) - radeon_crtc_handle_vblank(rdev, 4); - rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D5 vblank\n"); + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[4]) { + drm_handle_vblank(rdev->ddev, 4); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[4])) + radeon_crtc_handle_vblank(rdev, 4); + rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D5 vblank\n"); + break; case 1: /* D5 vline */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VLINE_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VLINE_INTERRUPT; - DRM_DEBUG("IH: D5 vline\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VLINE_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VLINE_INTERRUPT; + DRM_DEBUG("IH: D5 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -6596,23 +6616,27 @@ restart_ih: case 6: /* D6 vblank/vline */ switch (src_data) { case 0: /* D6 vblank */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[5]) { - drm_handle_vblank(rdev->ddev, 5); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[5])) - radeon_crtc_handle_vblank(rdev, 5); - rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D6 vblank\n"); + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[5]) { + drm_handle_vblank(rdev->ddev, 5); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[5])) + radeon_crtc_handle_vblank(rdev, 5); + rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D6 vblank\n"); + break; case 1: /* D6 vline */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VLINE_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VLINE_INTERRUPT; - DRM_DEBUG("IH: D6 vline\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VLINE_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VLINE_INTERRUPT; + DRM_DEBUG("IH: D6 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -6632,88 +6656,112 @@ restart_ih: case 42: /* HPD hotplug */ switch (src_data) { case 0: - if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD1\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD1\n"); + break; case 1: - if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD2\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD2\n"); + break; case 2: - if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD3\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD3\n"); + break; case 3: - if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD4\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD4\n"); + break; case 4: - if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD5\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD5\n"); + break; case 5: - if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD6\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD6\n"); + break; case 6: - if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_RX_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_RX_INTERRUPT; - queue_dp = true; - DRM_DEBUG("IH: HPD_RX 1\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 1\n"); + break; case 7: - if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_RX_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_RX_INTERRUPT; - queue_dp = true; - DRM_DEBUG("IH: HPD_RX 2\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 2\n"); + break; case 8: - if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_RX_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_RX_INTERRUPT; - queue_dp = true; - DRM_DEBUG("IH: HPD_RX 3\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 3\n"); + break; case 9: - if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_RX_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_RX_INTERRUPT; - queue_dp = true; - DRM_DEBUG("IH: HPD_RX 4\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 4\n"); + break; case 10: - if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_RX_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_RX_INTERRUPT; - queue_dp = true; - DRM_DEBUG("IH: HPD_RX 5\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 5\n"); + break; case 11: - if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_RX_INTERRUPT; - queue_dp = true; - DRM_DEBUG("IH: HPD_RX 6\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 6\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); -- cgit v1.2.3-70-g09d2 From bd833144a23dead304744dc748f5d72d7e92d315 Mon Sep 17 00:00:00 2001 From: Mario Kleiner Date: Fri, 3 Jul 2015 06:03:07 +0200 Subject: drm/amdgpu: Handle irqs only based on irq ring, not irq status regs. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a translation of the patch ... "drm/radeon: Handle irqs only based on irq ring, not irq status regs." ... for the vblank irq handling, to fix the same problem described in that patch on the new driver. Only compile tested due to lack of suitable hw. Reviewed-by: Christian König Signed-off-by: Mario Kleiner CC: Michel Dänzer CC: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/dce_v10_0.c | 22 ++++++++++++++-------- drivers/gpu/drm/amd/amdgpu/dce_v11_0.c | 22 ++++++++++++++-------- drivers/gpu/drm/amd/amdgpu/dce_v8_0.c | 22 ++++++++++++++-------- 3 files changed, 42 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c index 5cde635978f9..6e77964f1b64 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c @@ -3403,19 +3403,25 @@ static int dce_v10_0_crtc_irq(struct amdgpu_device *adev, switch (entry->src_data) { case 0: /* vblank */ - if (disp_int & interrupt_status_offsets[crtc].vblank) { + if (disp_int & interrupt_status_offsets[crtc].vblank) dce_v10_0_crtc_vblank_int_ack(adev, crtc); - if (amdgpu_irq_enabled(adev, source, irq_type)) { - drm_handle_vblank(adev->ddev, crtc); - } - DRM_DEBUG("IH: D%d vblank\n", crtc + 1); + else + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (amdgpu_irq_enabled(adev, source, irq_type)) { + drm_handle_vblank(adev->ddev, crtc); } + DRM_DEBUG("IH: D%d vblank\n", crtc + 1); + break; case 1: /* vline */ - if (disp_int & interrupt_status_offsets[crtc].vline) { + if (disp_int & interrupt_status_offsets[crtc].vline) dce_v10_0_crtc_vline_int_ack(adev, crtc); - DRM_DEBUG("IH: D%d vline\n", crtc + 1); - } + else + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + DRM_DEBUG("IH: D%d vline\n", crtc + 1); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", entry->src_id, entry->src_data); diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c index 95efd98b202d..7f7abb0e0be5 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c @@ -3402,19 +3402,25 @@ static int dce_v11_0_crtc_irq(struct amdgpu_device *adev, switch (entry->src_data) { case 0: /* vblank */ - if (disp_int & interrupt_status_offsets[crtc].vblank) { + if (disp_int & interrupt_status_offsets[crtc].vblank) dce_v11_0_crtc_vblank_int_ack(adev, crtc); - if (amdgpu_irq_enabled(adev, source, irq_type)) { - drm_handle_vblank(adev->ddev, crtc); - } - DRM_DEBUG("IH: D%d vblank\n", crtc + 1); + else + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (amdgpu_irq_enabled(adev, source, irq_type)) { + drm_handle_vblank(adev->ddev, crtc); } + DRM_DEBUG("IH: D%d vblank\n", crtc + 1); + break; case 1: /* vline */ - if (disp_int & interrupt_status_offsets[crtc].vline) { + if (disp_int & interrupt_status_offsets[crtc].vline) dce_v11_0_crtc_vline_int_ack(adev, crtc); - DRM_DEBUG("IH: D%d vline\n", crtc + 1); - } + else + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + DRM_DEBUG("IH: D%d vline\n", crtc + 1); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", entry->src_id, entry->src_data); diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c index aaca8d663f2c..08387dfd98a7 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c @@ -3237,19 +3237,25 @@ static int dce_v8_0_crtc_irq(struct amdgpu_device *adev, switch (entry->src_data) { case 0: /* vblank */ - if (disp_int & interrupt_status_offsets[crtc].vblank) { + if (disp_int & interrupt_status_offsets[crtc].vblank) WREG32(mmLB_VBLANK_STATUS + crtc_offsets[crtc], LB_VBLANK_STATUS__VBLANK_ACK_MASK); - if (amdgpu_irq_enabled(adev, source, irq_type)) { - drm_handle_vblank(adev->ddev, crtc); - } - DRM_DEBUG("IH: D%d vblank\n", crtc + 1); + else + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (amdgpu_irq_enabled(adev, source, irq_type)) { + drm_handle_vblank(adev->ddev, crtc); } + DRM_DEBUG("IH: D%d vblank\n", crtc + 1); + break; case 1: /* vline */ - if (disp_int & interrupt_status_offsets[crtc].vline) { + if (disp_int & interrupt_status_offsets[crtc].vline) WREG32(mmLB_VLINE_STATUS + crtc_offsets[crtc], LB_VLINE_STATUS__VLINE_ACK_MASK); - DRM_DEBUG("IH: D%d vline\n", crtc + 1); - } + else + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + DRM_DEBUG("IH: D%d vline\n", crtc + 1); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", entry->src_id, entry->src_data); -- cgit v1.2.3-70-g09d2 From 828202a382a06eda74202d4888d01a1078c68922 Mon Sep 17 00:00:00 2001 From: Grigori Goronzy Date: Fri, 3 Jul 2015 01:54:10 +0200 Subject: drm/radeon: use RCU query for GEM_BUSY syscall MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We don't need to call the (expensive) radeon_bo_wait, checking the fences via RCU is much faster. The reservation done by radeon_bo_wait does not save us from any race conditions. Reviewed-by: Christian König Signed-off-by: Grigori Goronzy Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_gem.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c index ac3c1310b953..7199e19eb8ba 100644 --- a/drivers/gpu/drm/radeon/radeon_gem.c +++ b/drivers/gpu/drm/radeon/radeon_gem.c @@ -428,7 +428,6 @@ int radeon_gem_mmap_ioctl(struct drm_device *dev, void *data, int radeon_gem_busy_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) { - struct radeon_device *rdev = dev->dev_private; struct drm_radeon_gem_busy *args = data; struct drm_gem_object *gobj; struct radeon_bo *robj; @@ -440,10 +439,16 @@ int radeon_gem_busy_ioctl(struct drm_device *dev, void *data, return -ENOENT; } robj = gem_to_radeon_bo(gobj); - r = radeon_bo_wait(robj, &cur_placement, true); + + r = reservation_object_test_signaled_rcu(robj->tbo.resv, true); + if (r == 0) + r = -EBUSY; + else + r = 0; + + cur_placement = ACCESS_ONCE(robj->tbo.mem.mem_type); args->domain = radeon_mem_type_to_domain(cur_placement); drm_gem_object_unreference_unlocked(gobj); - r = radeon_gem_handle_lockup(rdev, r); return r; } -- cgit v1.2.3-70-g09d2 From 54e03986133468e02cb01b76215e4d53a9cf6380 Mon Sep 17 00:00:00 2001 From: Grigori Goronzy Date: Fri, 3 Jul 2015 01:54:11 +0200 Subject: drm/radeon: fix HDP flushing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This was regressed by commit 39e7f6f8, although I don't know of any actual issues caused by it. The storage domain is read without TTM locking now, but the lock never helped to prevent any races. Reviewed-by: Christian König Cc: stable@vger.kernel.org Signed-off-by: Grigori Goronzy Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_gem.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c index 7199e19eb8ba..013ec7106e55 100644 --- a/drivers/gpu/drm/radeon/radeon_gem.c +++ b/drivers/gpu/drm/radeon/radeon_gem.c @@ -476,6 +476,7 @@ int radeon_gem_wait_idle_ioctl(struct drm_device *dev, void *data, r = ret; /* Flush HDP cache via MMIO if necessary */ + cur_placement = ACCESS_ONCE(robj->tbo.mem.mem_type); if (rdev->asic->mmio_hdp_flush && radeon_mem_type_to_domain(cur_placement) == RADEON_GEM_DOMAIN_VRAM) robj->rdev->asic->mmio_hdp_flush(rdev); -- cgit v1.2.3-70-g09d2 From 5e3c4f907043a7fae1b48e86536dc7b9efa07e29 Mon Sep 17 00:00:00 2001 From: Grigori Goronzy Date: Fri, 3 Jul 2015 01:54:12 +0200 Subject: drm/radeon: default to 2048 MB GART size on SI+ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Newer ASICs have more VRAM on average and allocating more GART as well can have advantages. Also see commit edcd26e8. Ideally, we should scale GART size based on actual VRAM size, but that requires significant restructuring of initialization. v2: extract small helper, apply to error paths Reviewed-by: Christian König Signed-off-by: Grigori Goronzy Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_device.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 2593b1168bd6..1a532a9bc3a3 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -1079,6 +1079,22 @@ static bool radeon_check_pot_argument(int arg) return (arg & (arg - 1)) == 0; } +/** + * Determine a sensible default GART size according to ASIC family. + * + * @family ASIC family name + */ +static int radeon_gart_size_auto(enum radeon_family family) +{ + /* default to a larger gart size on newer asics */ + if (family >= CHIP_TAHITI) + return 2048; + else if (family >= CHIP_RV770) + return 1024; + else + return 512; +} + /** * radeon_check_arguments - validate module params * @@ -1097,27 +1113,17 @@ static void radeon_check_arguments(struct radeon_device *rdev) } if (radeon_gart_size == -1) { - /* default to a larger gart size on newer asics */ - if (rdev->family >= CHIP_RV770) - radeon_gart_size = 1024; - else - radeon_gart_size = 512; + radeon_gart_size = radeon_gart_size_auto(rdev->family); } /* gtt size must be power of two and greater or equal to 32M */ if (radeon_gart_size < 32) { dev_warn(rdev->dev, "gart size (%d) too small\n", radeon_gart_size); - if (rdev->family >= CHIP_RV770) - radeon_gart_size = 1024; - else - radeon_gart_size = 512; + radeon_gart_size = radeon_gart_size_auto(rdev->family); } else if (!radeon_check_pot_argument(radeon_gart_size)) { dev_warn(rdev->dev, "gart size (%d) must be a power of 2\n", radeon_gart_size); - if (rdev->family >= CHIP_RV770) - radeon_gart_size = 1024; - else - radeon_gart_size = 512; + radeon_gart_size = radeon_gart_size_auto(rdev->family); } rdev->mc.gtt_size = (uint64_t)radeon_gart_size << 20; -- cgit v1.2.3-70-g09d2 From 866a92040392d844d151aa6a2ba15be2e6e5df4f Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 3 Jul 2015 11:54:28 +0300 Subject: drm/radeon: fix underflow in r600_cp_dispatch_texture() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "if (pass_size > buf->total)" can underflow so I have changed the type of size and pass_size to unsigned to avoid this problem. Reviewed-by: Christian König Signed-off-by: Dan Carpenter Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/r600_cp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/r600_cp.c b/drivers/gpu/drm/radeon/r600_cp.c index 09e3f39925fa..98f9adaccc3d 100644 --- a/drivers/gpu/drm/radeon/r600_cp.c +++ b/drivers/gpu/drm/radeon/r600_cp.c @@ -2483,7 +2483,7 @@ int r600_cp_dispatch_texture(struct drm_device *dev, struct drm_buf *buf; u32 *buffer; const u8 __user *data; - int size, pass_size; + unsigned int size, pass_size; u64 src_offset, dst_offset; if (!radeon_check_offset(dev_priv, tex->offset)) { -- cgit v1.2.3-70-g09d2 From aa43c5ff737dac5dcfccd12d23abeefbdf0579c7 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Sat, 4 Jul 2015 11:22:30 +0200 Subject: NET: hamradio: Fix IP over bpq encapsulation. Since 1d5da757da860a6916adbf68b09e868062b4b3b8 (ax25: Stop using magic neighbour cache operations.) any attempt to transmit IP packets over a bpqether device will result in a message like "Dead loop on virtual device bpq0, fix it urgently!" Fix suggested by Eric W. Biederman . Signed-off-by: Ralf Baechle Cc: # 4.1 Signed-off-by: David S. Miller --- drivers/net/hamradio/bpqether.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index 7856b6ccf5c5..d95a50ae996d 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -482,6 +482,7 @@ static void bpq_setup(struct net_device *dev) memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN); dev->flags = 0; + dev->features = NETIF_F_LLTX; /* Allow recursion */ #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) dev->header_ops = &ax25_header_ops; -- cgit v1.2.3-70-g09d2 From cfa520056407acaa29f3aa7aee10c929b371c7cf Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Sun, 5 Jul 2015 12:16:27 -0500 Subject: net: phy: add dependency on HAS_IOMEM to MDIO_BUS_MUX_MMIOREG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On UML builds, mdio-mux-mmioreg.c fails to compile: drivers/net/phy/mdio-mux-mmioreg.c:50:3: error: implicit declaration of function ‘ioremap’ [-Werror=implicit-function-declaration] drivers/net/phy/mdio-mux-mmioreg.c:63:3: error: implicit declaration of function ‘iounmap’ [-Werror=implicit-function-declaration] This is due to CONFIG_OF now being user selectable. Add a dependency on HAS_IOMEM to fix this. Signed-off-by: Rob Herring Cc: Florian Fainelli Cc: David S. Miller Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index cf18940f4e84..cb86d7a01542 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -191,7 +191,7 @@ config MDIO_BUS_MUX_GPIO config MDIO_BUS_MUX_MMIOREG tristate "Support for MMIO device-controlled MDIO bus multiplexers" - depends on OF_MDIO + depends on OF_MDIO && HAS_IOMEM select MDIO_BUS_MUX help This module provides a driver for MDIO bus multiplexers that -- cgit v1.2.3-70-g09d2 From cfbfd86bfde15020bccde377e11586ee5c8b701d Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Mon, 6 Jul 2015 11:57:37 -0500 Subject: amd-xgbe: Fix DMA API debug warning When running a kernel configured with CONFIG_DMA_API_DEBUG=y a warning is issued: DMA-API: device driver tries to sync DMA memory it has not allocated This warning is the result of mapping the full range of the Rx buffer pages allocated and then performing a dma_sync_single_for_cpu against a calculated DMA address. The proper thing to do is to use the dma_sync_single_range_for_cpu with a base DMA address and an offset. Reported-by: Kim Phillips Signed-off-by: Tom Lendacky Tested-by: Kim Phillips Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-desc.c | 3 ++- drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 11 +++++++---- drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 17 +++++++++++------ drivers/net/ethernet/amd/xgbe/xgbe.h | 3 ++- 4 files changed, 22 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c index 661cdaa7ea96..b3bc87fe3764 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c @@ -303,7 +303,8 @@ static void xgbe_set_buffer_data(struct xgbe_buffer_data *bd, get_page(pa->pages); bd->pa = *pa; - bd->dma = pa->pages_dma + pa->pages_offset; + bd->dma_base = pa->pages_dma; + bd->dma_off = pa->pages_offset; bd->dma_len = len; pa->pages_offset += len; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c index 506e832c9e9a..a4473d8ff4fa 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c @@ -1110,6 +1110,7 @@ static void xgbe_rx_desc_reset(struct xgbe_prv_data *pdata, unsigned int rx_usecs = pdata->rx_usecs; unsigned int rx_frames = pdata->rx_frames; unsigned int inte; + dma_addr_t hdr_dma, buf_dma; if (!rx_usecs && !rx_frames) { /* No coalescing, interrupt for every descriptor */ @@ -1129,10 +1130,12 @@ static void xgbe_rx_desc_reset(struct xgbe_prv_data *pdata, * Set buffer 2 (hi) address to buffer dma address (hi) and * set control bits OWN and INTE */ - rdesc->desc0 = cpu_to_le32(lower_32_bits(rdata->rx.hdr.dma)); - rdesc->desc1 = cpu_to_le32(upper_32_bits(rdata->rx.hdr.dma)); - rdesc->desc2 = cpu_to_le32(lower_32_bits(rdata->rx.buf.dma)); - rdesc->desc3 = cpu_to_le32(upper_32_bits(rdata->rx.buf.dma)); + hdr_dma = rdata->rx.hdr.dma_base + rdata->rx.hdr.dma_off; + buf_dma = rdata->rx.buf.dma_base + rdata->rx.buf.dma_off; + rdesc->desc0 = cpu_to_le32(lower_32_bits(hdr_dma)); + rdesc->desc1 = cpu_to_le32(upper_32_bits(hdr_dma)); + rdesc->desc2 = cpu_to_le32(lower_32_bits(buf_dma)); + rdesc->desc3 = cpu_to_le32(upper_32_bits(buf_dma)); XGMAC_SET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, INTE, inte); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index 1e9c28d19ef8..aae9d5ecd182 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -1765,8 +1765,9 @@ static struct sk_buff *xgbe_create_skb(struct xgbe_prv_data *pdata, /* Start with the header buffer which may contain just the header * or the header plus data */ - dma_sync_single_for_cpu(pdata->dev, rdata->rx.hdr.dma, - rdata->rx.hdr.dma_len, DMA_FROM_DEVICE); + dma_sync_single_range_for_cpu(pdata->dev, rdata->rx.hdr.dma_base, + rdata->rx.hdr.dma_off, + rdata->rx.hdr.dma_len, DMA_FROM_DEVICE); packet = page_address(rdata->rx.hdr.pa.pages) + rdata->rx.hdr.pa.pages_offset; @@ -1778,8 +1779,11 @@ static struct sk_buff *xgbe_create_skb(struct xgbe_prv_data *pdata, len -= copy_len; if (len) { /* Add the remaining data as a frag */ - dma_sync_single_for_cpu(pdata->dev, rdata->rx.buf.dma, - rdata->rx.buf.dma_len, DMA_FROM_DEVICE); + dma_sync_single_range_for_cpu(pdata->dev, + rdata->rx.buf.dma_base, + rdata->rx.buf.dma_off, + rdata->rx.buf.dma_len, + DMA_FROM_DEVICE); skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, rdata->rx.buf.pa.pages, @@ -1945,8 +1949,9 @@ read_again: if (!skb) error = 1; } else if (rdesc_len) { - dma_sync_single_for_cpu(pdata->dev, - rdata->rx.buf.dma, + dma_sync_single_range_for_cpu(pdata->dev, + rdata->rx.buf.dma_base, + rdata->rx.buf.dma_off, rdata->rx.buf.dma_len, DMA_FROM_DEVICE); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index 63d72a140053..717ce21b6077 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -337,7 +337,8 @@ struct xgbe_buffer_data { struct xgbe_page_alloc pa; struct xgbe_page_alloc pa_unmap; - dma_addr_t dma; + dma_addr_t dma_base; + unsigned long dma_off; unsigned int dma_len; }; -- cgit v1.2.3-70-g09d2 From 6c3e921b18edca290099adfddde8a50236bf2d80 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Mon, 6 Jul 2015 20:34:55 +0200 Subject: net: fec: Ensure clocks are enabled while using mdio bus When a switch is attached to the mdio bus, the mdio bus can be used while the interface is not open. If the IPG clock is not enabled, MDIO reads/writes will simply time out. Add support for runtime PM to control this clock. Enable/disable this clock using runtime PM, with open()/close() and mdio read()/write() function triggering runtime PM operations. Since PM is optional, the IPG clock is enabled at probe and is no longer modified by fec_enet_clk_enable(), thus if PM is not enabled in the kernel, it is guaranteed the clock is running when MDIO operations are performed. Signed-off-by: Andrew Lunn Acked-by: Fugang Duan Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 88 ++++++++++++++++++++++++++----- 1 file changed, 75 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 1f89c59b4353..42e20e5385ac 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -77,6 +78,7 @@ static void fec_enet_itr_coal_init(struct net_device *ndev); #define FEC_ENET_RAEM_V 0x8 #define FEC_ENET_RAFL_V 0x8 #define FEC_ENET_OPD_V 0xFFF0 +#define FEC_MDIO_PM_TIMEOUT 100 /* ms */ static struct platform_device_id fec_devtype[] = { { @@ -1767,7 +1769,13 @@ static void fec_enet_adjust_link(struct net_device *ndev) static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum) { struct fec_enet_private *fep = bus->priv; + struct device *dev = &fep->pdev->dev; unsigned long time_left; + int ret = 0; + + ret = pm_runtime_get_sync(dev); + if (IS_ERR_VALUE(ret)) + return ret; fep->mii_timeout = 0; init_completion(&fep->mdio_done); @@ -1783,18 +1791,30 @@ static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum) if (time_left == 0) { fep->mii_timeout = 1; netdev_err(fep->netdev, "MDIO read timeout\n"); - return -ETIMEDOUT; + ret = -ETIMEDOUT; + goto out; } - /* return value */ - return FEC_MMFR_DATA(readl(fep->hwp + FEC_MII_DATA)); + ret = FEC_MMFR_DATA(readl(fep->hwp + FEC_MII_DATA)); + +out: + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + + return ret; } static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value) { struct fec_enet_private *fep = bus->priv; + struct device *dev = &fep->pdev->dev; unsigned long time_left; + int ret = 0; + + ret = pm_runtime_get_sync(dev); + if (IS_ERR_VALUE(ret)) + return ret; fep->mii_timeout = 0; init_completion(&fep->mdio_done); @@ -1811,10 +1831,13 @@ static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum, if (time_left == 0) { fep->mii_timeout = 1; netdev_err(fep->netdev, "MDIO write timeout\n"); - return -ETIMEDOUT; + ret = -ETIMEDOUT; } - return 0; + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + + return ret; } static int fec_enet_clk_enable(struct net_device *ndev, bool enable) @@ -1826,9 +1849,6 @@ static int fec_enet_clk_enable(struct net_device *ndev, bool enable) ret = clk_prepare_enable(fep->clk_ahb); if (ret) return ret; - ret = clk_prepare_enable(fep->clk_ipg); - if (ret) - goto failed_clk_ipg; if (fep->clk_enet_out) { ret = clk_prepare_enable(fep->clk_enet_out); if (ret) @@ -1852,7 +1872,6 @@ static int fec_enet_clk_enable(struct net_device *ndev, bool enable) } } else { clk_disable_unprepare(fep->clk_ahb); - clk_disable_unprepare(fep->clk_ipg); if (fep->clk_enet_out) clk_disable_unprepare(fep->clk_enet_out); if (fep->clk_ptp) { @@ -1874,8 +1893,6 @@ failed_clk_ptp: if (fep->clk_enet_out) clk_disable_unprepare(fep->clk_enet_out); failed_clk_enet_out: - clk_disable_unprepare(fep->clk_ipg); -failed_clk_ipg: clk_disable_unprepare(fep->clk_ahb); return ret; @@ -2847,10 +2864,14 @@ fec_enet_open(struct net_device *ndev) struct fec_enet_private *fep = netdev_priv(ndev); int ret; + ret = pm_runtime_get_sync(&fep->pdev->dev); + if (IS_ERR_VALUE(ret)) + return ret; + pinctrl_pm_select_default_state(&fep->pdev->dev); ret = fec_enet_clk_enable(ndev, true); if (ret) - return ret; + goto clk_enable; /* I should reset the ring buffers here, but I don't yet know * a simple way to do that. @@ -2881,6 +2902,9 @@ err_enet_mii_probe: fec_enet_free_buffers(ndev); err_enet_alloc: fec_enet_clk_enable(ndev, false); +clk_enable: + pm_runtime_mark_last_busy(&fep->pdev->dev); + pm_runtime_put_autosuspend(&fep->pdev->dev); pinctrl_pm_select_sleep_state(&fep->pdev->dev); return ret; } @@ -2903,6 +2927,9 @@ fec_enet_close(struct net_device *ndev) fec_enet_clk_enable(ndev, false); pinctrl_pm_select_sleep_state(&fep->pdev->dev); + pm_runtime_mark_last_busy(&fep->pdev->dev); + pm_runtime_put_autosuspend(&fep->pdev->dev); + fec_enet_free_buffers(ndev); return 0; @@ -3388,6 +3415,10 @@ fec_probe(struct platform_device *pdev) if (ret) goto failed_clk; + ret = clk_prepare_enable(fep->clk_ipg); + if (ret) + goto failed_clk_ipg; + fep->reg_phy = devm_regulator_get(&pdev->dev, "phy"); if (!IS_ERR(fep->reg_phy)) { ret = regulator_enable(fep->reg_phy); @@ -3434,6 +3465,8 @@ fec_probe(struct platform_device *pdev) netif_carrier_off(ndev); fec_enet_clk_enable(ndev, false); pinctrl_pm_select_sleep_state(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); ret = register_netdev(ndev); if (ret) @@ -3447,6 +3480,12 @@ fec_probe(struct platform_device *pdev) fep->rx_copybreak = COPYBREAK_DEFAULT; INIT_WORK(&fep->tx_timeout_work, fec_enet_timeout_work); + + pm_runtime_set_autosuspend_delay(&pdev->dev, FEC_MDIO_PM_TIMEOUT); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_mark_last_busy(&pdev->dev); + pm_runtime_put_autosuspend(&pdev->dev); + return 0; failed_register: @@ -3457,6 +3496,8 @@ failed_init: if (fep->reg_phy) regulator_disable(fep->reg_phy); failed_regulator: + clk_disable_unprepare(fep->clk_ipg); +failed_clk_ipg: fec_enet_clk_enable(ndev, false); failed_clk: failed_phy: @@ -3568,7 +3609,28 @@ failed_clk: return ret; } -static SIMPLE_DEV_PM_OPS(fec_pm_ops, fec_suspend, fec_resume); +static int __maybe_unused fec_runtime_suspend(struct device *dev) +{ + struct net_device *ndev = dev_get_drvdata(dev); + struct fec_enet_private *fep = netdev_priv(ndev); + + clk_disable_unprepare(fep->clk_ipg); + + return 0; +} + +static int __maybe_unused fec_runtime_resume(struct device *dev) +{ + struct net_device *ndev = dev_get_drvdata(dev); + struct fec_enet_private *fep = netdev_priv(ndev); + + return clk_prepare_enable(fep->clk_ipg); +} + +static const struct dev_pm_ops fec_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(fec_suspend, fec_resume) + SET_RUNTIME_PM_OPS(fec_runtime_suspend, fec_runtime_resume, NULL) +}; static struct platform_driver fec_driver = { .driver = { -- cgit v1.2.3-70-g09d2 From b5a983f3141239b5b0b4a4e66efa31f8a26354b8 Mon Sep 17 00:00:00 2001 From: Mazhar Rana Date: Tue, 7 Jul 2015 15:04:50 +0530 Subject: bonding: "primary_reselect" with "failure" is not working properly When "primary_reselect" is set to "failure", primary interface should not become active until current active slave is down. But if we set first member of bond device as a "primary" interface and "primary_reselect" is set to "failure" then whenever primary interface's link get back(up) it become active slave even if current active slave is still up. With this patch, "bond_find_best_slave" will not traverse members if primary interface is not candidate for failover/reselection and current active slave is still up. Signed-off-by: Mazhar Rana Signed-off-by: Jay Vosburgh Signed-off-by: Jay Vosburgh Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 51 +++++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 19eb990d398c..317a49480475 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -689,40 +689,57 @@ out: } -static bool bond_should_change_active(struct bonding *bond) +static struct slave *bond_choose_primary_or_current(struct bonding *bond) { struct slave *prim = rtnl_dereference(bond->primary_slave); struct slave *curr = rtnl_dereference(bond->curr_active_slave); - if (!prim || !curr || curr->link != BOND_LINK_UP) - return true; + if (!prim || prim->link != BOND_LINK_UP) { + if (!curr || curr->link != BOND_LINK_UP) + return NULL; + return curr; + } + if (bond->force_primary) { bond->force_primary = false; - return true; + return prim; + } + + if (!curr || curr->link != BOND_LINK_UP) + return prim; + + /* At this point, prim and curr are both up */ + switch (bond->params.primary_reselect) { + case BOND_PRI_RESELECT_ALWAYS: + return prim; + case BOND_PRI_RESELECT_BETTER: + if (prim->speed < curr->speed) + return curr; + if (prim->speed == curr->speed && prim->duplex <= curr->duplex) + return curr; + return prim; + case BOND_PRI_RESELECT_FAILURE: + return curr; + default: + netdev_err(bond->dev, "impossible primary_reselect %d\n", + bond->params.primary_reselect); + return curr; } - if (bond->params.primary_reselect == BOND_PRI_RESELECT_BETTER && - (prim->speed < curr->speed || - (prim->speed == curr->speed && prim->duplex <= curr->duplex))) - return false; - if (bond->params.primary_reselect == BOND_PRI_RESELECT_FAILURE) - return false; - return true; } /** - * find_best_interface - select the best available slave to be the active one + * bond_find_best_slave - select the best available slave to be the active one * @bond: our bonding struct */ static struct slave *bond_find_best_slave(struct bonding *bond) { - struct slave *slave, *bestslave = NULL, *primary; + struct slave *slave, *bestslave = NULL; struct list_head *iter; int mintime = bond->params.updelay; - primary = rtnl_dereference(bond->primary_slave); - if (primary && primary->link == BOND_LINK_UP && - bond_should_change_active(bond)) - return primary; + slave = bond_choose_primary_or_current(bond); + if (slave) + return slave; bond_for_each_slave(bond, slave, iter) { if (slave->link == BOND_LINK_UP) -- cgit v1.2.3-70-g09d2 From 9e9f665a18008999e749bd41394efcbf5c37a726 Mon Sep 17 00:00:00 2001 From: Daniel Pieczko Date: Tue, 7 Jul 2015 11:37:00 +0100 Subject: sfc: refactor code in efx_ef10_set_mac_address() Re-organize the structure of error handling to avoid having to duplicate the netif_err() around the ifdefs. The only change to the behaviour of the error-handling is that the PF's data structure to record VF details should only be updated if the original command succeeded. Signed-off-by: Shradha Shah Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 45 ++++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 847643455468..9740cd02f81d 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -3829,38 +3829,27 @@ static int efx_ef10_set_mac_address(struct efx_nic *efx) efx_net_open(efx->net_dev); netif_device_attach(efx->net_dev); -#if !defined(CONFIG_SFC_SRIOV) - if (rc == -EPERM) - netif_err(efx, drv, efx->net_dev, - "Cannot change MAC address; use sfboot to enable mac-spoofing" - " on this interface\n"); -#else - if (rc == -EPERM) { +#ifdef CONFIG_SFC_SRIOV + if (efx->pci_dev->is_virtfn && efx->pci_dev->physfn) { struct pci_dev *pci_dev_pf = efx->pci_dev->physfn; - /* Switch to PF and change MAC address on vport */ - if (efx->pci_dev->is_virtfn && pci_dev_pf) { - struct efx_nic *efx_pf = pci_get_drvdata(pci_dev_pf); + if (rc == -EPERM) { + struct efx_nic *efx_pf; - if (!efx_ef10_sriov_set_vf_mac(efx_pf, - nic_data->vf_index, - efx->net_dev->dev_addr)) - return 0; - } - netif_err(efx, drv, efx->net_dev, - "Cannot change MAC address; use sfboot to enable mac-spoofing" - " on this interface\n"); - } else if (efx->pci_dev->is_virtfn) { - /* Successfully changed by VF (with MAC spoofing), so update the - * parent PF if possible. - */ - struct pci_dev *pci_dev_pf = efx->pci_dev->physfn; + /* Switch to PF and change MAC address on vport */ + efx_pf = pci_get_drvdata(pci_dev_pf); - if (pci_dev_pf) { + rc = efx_ef10_sriov_set_vf_mac(efx_pf, + nic_data->vf_index, + efx->net_dev->dev_addr); + } else if (!rc) { struct efx_nic *efx_pf = pci_get_drvdata(pci_dev_pf); struct efx_ef10_nic_data *nic_data = efx_pf->nic_data; unsigned int i; + /* MAC address successfully changed by VF (with MAC + * spoofing) so update the parent PF if possible. + */ for (i = 0; i < efx_pf->vf_count; ++i) { struct ef10_vf *vf = nic_data->vf + i; @@ -3871,8 +3860,14 @@ static int efx_ef10_set_mac_address(struct efx_nic *efx) } } } - } + } else #endif + if (rc == -EPERM) { + netif_err(efx, drv, efx->net_dev, + "Cannot change MAC address; use sfboot to enable" + " mac-spoofing on this interface\n"); + } + return rc; } -- cgit v1.2.3-70-g09d2 From 7a186f4703de6f4b7feb5d09735b096145b8918c Mon Sep 17 00:00:00 2001 From: Daniel Pieczko Date: Tue, 7 Jul 2015 11:37:19 +0100 Subject: sfc: add legacy method for changing a PF's MAC address Some versions of MCFW do not support the MC_CMD_VADAPTOR_SET_MAC command, and ENOSYS will be returned. If the PF created its own vport, the function's datapath must be stopped and the vport can be reconfigured to reflect the new MAC address. If the MCFW created the vport for the PF (which is the case when the nic_data->vport_mac is blank), nothing further needs to be done as the vport is not under the control of the PF. This only applies to PFs because the MCFW in question does not support VFs. Signed-off-by: Shradha Shah Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 120 ++++++++++++++++++++++++++++++++++ drivers/net/ethernet/sfc/ef10_sriov.c | 42 ------------ drivers/net/ethernet/sfc/ef10_sriov.h | 6 ++ 3 files changed, 126 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 9740cd02f81d..e0cb3617f549 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -101,6 +101,11 @@ static unsigned int efx_ef10_mem_map_size(struct efx_nic *efx) return resource_size(&efx->pci_dev->resource[bar]); } +static bool efx_ef10_is_vf(struct efx_nic *efx) +{ + return efx->type->is_vf; +} + static int efx_ef10_get_pf_index(struct efx_nic *efx) { MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_FUNCTION_INFO_OUT_LEN); @@ -677,6 +682,48 @@ static int efx_ef10_probe_pf(struct efx_nic *efx) return efx_ef10_probe(efx); } +int efx_ef10_vadaptor_alloc(struct efx_nic *efx, unsigned int port_id) +{ + MCDI_DECLARE_BUF(inbuf, MC_CMD_VADAPTOR_ALLOC_IN_LEN); + + MCDI_SET_DWORD(inbuf, VADAPTOR_ALLOC_IN_UPSTREAM_PORT_ID, port_id); + return efx_mcdi_rpc(efx, MC_CMD_VADAPTOR_ALLOC, inbuf, sizeof(inbuf), + NULL, 0, NULL); +} + +int efx_ef10_vadaptor_free(struct efx_nic *efx, unsigned int port_id) +{ + MCDI_DECLARE_BUF(inbuf, MC_CMD_VADAPTOR_FREE_IN_LEN); + + MCDI_SET_DWORD(inbuf, VADAPTOR_FREE_IN_UPSTREAM_PORT_ID, port_id); + return efx_mcdi_rpc(efx, MC_CMD_VADAPTOR_FREE, inbuf, sizeof(inbuf), + NULL, 0, NULL); +} + +int efx_ef10_vport_add_mac(struct efx_nic *efx, + unsigned int port_id, u8 *mac) +{ + MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_ADD_MAC_ADDRESS_IN_LEN); + + MCDI_SET_DWORD(inbuf, VPORT_ADD_MAC_ADDRESS_IN_VPORT_ID, port_id); + ether_addr_copy(MCDI_PTR(inbuf, VPORT_ADD_MAC_ADDRESS_IN_MACADDR), mac); + + return efx_mcdi_rpc(efx, MC_CMD_VPORT_ADD_MAC_ADDRESS, inbuf, + sizeof(inbuf), NULL, 0, NULL); +} + +int efx_ef10_vport_del_mac(struct efx_nic *efx, + unsigned int port_id, u8 *mac) +{ + MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_DEL_MAC_ADDRESS_IN_LEN); + + MCDI_SET_DWORD(inbuf, VPORT_DEL_MAC_ADDRESS_IN_VPORT_ID, port_id); + ether_addr_copy(MCDI_PTR(inbuf, VPORT_DEL_MAC_ADDRESS_IN_MACADDR), mac); + + return efx_mcdi_rpc(efx, MC_CMD_VPORT_DEL_MAC_ADDRESS, inbuf, + sizeof(inbuf), NULL, 0, NULL); +} + #ifdef CONFIG_SFC_SRIOV static int efx_ef10_probe_vf(struct efx_nic *efx) { @@ -3804,6 +3851,72 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) WARN_ON(remove_failed); } +static int efx_ef10_vport_set_mac_address(struct efx_nic *efx) +{ + struct efx_ef10_nic_data *nic_data = efx->nic_data; + u8 mac_old[ETH_ALEN]; + int rc, rc2; + + /* Only reconfigure a PF-created vport */ + if (is_zero_ether_addr(nic_data->vport_mac)) + return 0; + + efx_device_detach_sync(efx); + efx_net_stop(efx->net_dev); + down_write(&efx->filter_sem); + efx_ef10_filter_table_remove(efx); + up_write(&efx->filter_sem); + + rc = efx_ef10_vadaptor_free(efx, nic_data->vport_id); + if (rc) + goto restore_filters; + + ether_addr_copy(mac_old, nic_data->vport_mac); + rc = efx_ef10_vport_del_mac(efx, nic_data->vport_id, + nic_data->vport_mac); + if (rc) + goto restore_vadaptor; + + rc = efx_ef10_vport_add_mac(efx, nic_data->vport_id, + efx->net_dev->dev_addr); + if (!rc) { + ether_addr_copy(nic_data->vport_mac, efx->net_dev->dev_addr); + } else { + rc2 = efx_ef10_vport_add_mac(efx, nic_data->vport_id, mac_old); + if (rc2) { + /* Failed to add original MAC, so clear vport_mac */ + eth_zero_addr(nic_data->vport_mac); + goto reset_nic; + } + } + +restore_vadaptor: + rc2 = efx_ef10_vadaptor_alloc(efx, nic_data->vport_id); + if (rc2) + goto reset_nic; +restore_filters: + down_write(&efx->filter_sem); + rc2 = efx_ef10_filter_table_probe(efx); + up_write(&efx->filter_sem); + if (rc2) + goto reset_nic; + + rc2 = efx_net_open(efx->net_dev); + if (rc2) + goto reset_nic; + + netif_device_attach(efx->net_dev); + + return rc; + +reset_nic: + netif_err(efx, drv, efx->net_dev, + "Failed to restore when changing MAC address - scheduling reset\n"); + efx_schedule_reset(efx, RESET_TYPE_DATAPATH); + + return rc ? rc : rc2; +} + static int efx_ef10_set_mac_address(struct efx_nic *efx) { MCDI_DECLARE_BUF(inbuf, MC_CMD_VADAPTOR_SET_MAC_IN_LEN); @@ -3866,6 +3979,13 @@ static int efx_ef10_set_mac_address(struct efx_nic *efx) netif_err(efx, drv, efx->net_dev, "Cannot change MAC address; use sfboot to enable" " mac-spoofing on this interface\n"); + } else if (rc == -ENOSYS && !efx_ef10_is_vf(efx)) { + /* If the active MCFW does not support MC_CMD_VADAPTOR_SET_MAC + * fall-back to the method of changing the MAC address on the + * vport. This only applies to PFs because such versions of + * MCFW do not support VFs. + */ + rc = efx_ef10_vport_set_mac_address(efx); } return rc; diff --git a/drivers/net/ethernet/sfc/ef10_sriov.c b/drivers/net/ethernet/sfc/ef10_sriov.c index 6c9b6e45509a..7485f71b4e2f 100644 --- a/drivers/net/ethernet/sfc/ef10_sriov.c +++ b/drivers/net/ethernet/sfc/ef10_sriov.c @@ -29,30 +29,6 @@ static int efx_ef10_evb_port_assign(struct efx_nic *efx, unsigned int port_id, NULL, 0, NULL); } -static int efx_ef10_vport_add_mac(struct efx_nic *efx, - unsigned int port_id, u8 *mac) -{ - MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_ADD_MAC_ADDRESS_IN_LEN); - - MCDI_SET_DWORD(inbuf, VPORT_ADD_MAC_ADDRESS_IN_VPORT_ID, port_id); - ether_addr_copy(MCDI_PTR(inbuf, VPORT_ADD_MAC_ADDRESS_IN_MACADDR), mac); - - return efx_mcdi_rpc(efx, MC_CMD_VPORT_ADD_MAC_ADDRESS, inbuf, - sizeof(inbuf), NULL, 0, NULL); -} - -static int efx_ef10_vport_del_mac(struct efx_nic *efx, - unsigned int port_id, u8 *mac) -{ - MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_DEL_MAC_ADDRESS_IN_LEN); - - MCDI_SET_DWORD(inbuf, VPORT_DEL_MAC_ADDRESS_IN_VPORT_ID, port_id); - ether_addr_copy(MCDI_PTR(inbuf, VPORT_DEL_MAC_ADDRESS_IN_MACADDR), mac); - - return efx_mcdi_rpc(efx, MC_CMD_VPORT_DEL_MAC_ADDRESS, inbuf, - sizeof(inbuf), NULL, 0, NULL); -} - static int efx_ef10_vswitch_alloc(struct efx_nic *efx, unsigned int port_id, unsigned int vswitch_type) { @@ -136,24 +112,6 @@ static int efx_ef10_vport_free(struct efx_nic *efx, unsigned int port_id) NULL, 0, NULL); } -static int efx_ef10_vadaptor_alloc(struct efx_nic *efx, unsigned int port_id) -{ - MCDI_DECLARE_BUF(inbuf, MC_CMD_VADAPTOR_ALLOC_IN_LEN); - - MCDI_SET_DWORD(inbuf, VADAPTOR_ALLOC_IN_UPSTREAM_PORT_ID, port_id); - return efx_mcdi_rpc(efx, MC_CMD_VADAPTOR_ALLOC, inbuf, sizeof(inbuf), - NULL, 0, NULL); -} - -static int efx_ef10_vadaptor_free(struct efx_nic *efx, unsigned int port_id) -{ - MCDI_DECLARE_BUF(inbuf, MC_CMD_VADAPTOR_FREE_IN_LEN); - - MCDI_SET_DWORD(inbuf, VADAPTOR_FREE_IN_UPSTREAM_PORT_ID, port_id); - return efx_mcdi_rpc(efx, MC_CMD_VADAPTOR_FREE, inbuf, sizeof(inbuf), - NULL, 0, NULL); -} - static void efx_ef10_sriov_free_vf_vports(struct efx_nic *efx) { struct efx_ef10_nic_data *nic_data = efx->nic_data; diff --git a/drivers/net/ethernet/sfc/ef10_sriov.h b/drivers/net/ethernet/sfc/ef10_sriov.h index db4ef537c610..6d25b92cb45e 100644 --- a/drivers/net/ethernet/sfc/ef10_sriov.h +++ b/drivers/net/ethernet/sfc/ef10_sriov.h @@ -65,5 +65,11 @@ int efx_ef10_vswitching_restore_pf(struct efx_nic *efx); int efx_ef10_vswitching_restore_vf(struct efx_nic *efx); void efx_ef10_vswitching_remove_pf(struct efx_nic *efx); void efx_ef10_vswitching_remove_vf(struct efx_nic *efx); +int efx_ef10_vport_add_mac(struct efx_nic *efx, + unsigned int port_id, u8 *mac); +int efx_ef10_vport_del_mac(struct efx_nic *efx, + unsigned int port_id, u8 *mac); +int efx_ef10_vadaptor_alloc(struct efx_nic *efx, unsigned int port_id); +int efx_ef10_vadaptor_free(struct efx_nic *efx, unsigned int port_id); #endif /* EF10_SRIOV_H */ -- cgit v1.2.3-70-g09d2 From 535a61777f44eebcb71f2a6866f95b17ee0f13c7 Mon Sep 17 00:00:00 2001 From: Daniel Pieczko Date: Tue, 7 Jul 2015 11:37:33 +0100 Subject: sfc: suppress handled MCDI failures when changing the MAC address Signed-off-by: Shradha Shah Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index e0cb3617f549..605cc8948594 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -3933,8 +3933,8 @@ static int efx_ef10_set_mac_address(struct efx_nic *efx) efx->net_dev->dev_addr); MCDI_SET_DWORD(inbuf, VADAPTOR_SET_MAC_IN_UPSTREAM_PORT_ID, nic_data->vport_id); - rc = efx_mcdi_rpc(efx, MC_CMD_VADAPTOR_SET_MAC, inbuf, - sizeof(inbuf), NULL, 0, NULL); + rc = efx_mcdi_rpc_quiet(efx, MC_CMD_VADAPTOR_SET_MAC, inbuf, + sizeof(inbuf), NULL, 0, NULL); efx_ef10_filter_table_probe(efx); up_write(&efx->filter_sem); @@ -3986,6 +3986,9 @@ static int efx_ef10_set_mac_address(struct efx_nic *efx) * MCFW do not support VFs. */ rc = efx_ef10_vport_set_mac_address(efx); + } else { + efx_mcdi_display_error(efx, MC_CMD_VADAPTOR_SET_MAC, + sizeof(inbuf), NULL, 0, rc); } return rc; -- cgit v1.2.3-70-g09d2 From 1973db0df7c3bd69de2a1041d3364567287771d9 Mon Sep 17 00:00:00 2001 From: Mugunthan V N Date: Tue, 7 Jul 2015 18:30:39 +0530 Subject: drivers: net: cpsw: fix crash while accessing second slave ethernet interface When cpsw's number of slave is set to 1 in device tree and while accessing second slave ndev and priv in cpsw_tx_interrupt(), there is a kernel crash. This is due to cpsw_get_slave_priv() not verifying number of slaves while retriving netdev priv and returns a invalid memory region. Fixing the issue by introducing number of slave check in cpsw_get_slave_priv() and cpsw_get_slave_ndev(). [ 15.879589] Unable to handle kernel paging request at virtual address 0f0e142c [ 15.888540] pgd = ed374000 [ 15.891359] [0f0e142c] *pgd=00000000 [ 15.895105] Internal error: Oops: 5 [#1] SMP ARM [ 15.899936] Modules linked in: [ 15.903139] CPU: 0 PID: 593 Comm: udhcpc Tainted: G W 4.1.0-12205-gfda8b18-dirty #10 [ 15.912386] Hardware name: Generic AM43 (Flattened Device Tree) [ 15.918557] task: ed2a2e00 ti: ed3fe000 task.ti: ed3fe000 [ 15.924187] PC is at cpsw_tx_interrupt+0x30/0x44 [ 15.929008] LR is at _raw_spin_unlock_irqrestore+0x40/0x44 [ 15.934726] pc : [] lr : [] psr: 20000193 [ 15.934726] sp : ed3ffc08 ip : ed2a2e40 fp : 00000000 [ 15.946685] r10: c0969ce8 r9 : c0969cfc r8 : 00000000 [ 15.952129] r7 : 000000c6 r6 : ee54ab00 r5 : ee169c64 r4 : ee534e00 [ 15.958932] r3 : 0f0e0d0c r2 : 00000000 r1 : ed3ffbc0 r0 : 00000001 [ 15.965735] Flags: nzCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment user [ 15.973261] Control: 10c5387d Table: ad374059 DAC: 00000015 [ 15.979246] Process udhcpc (pid: 593, stack limit = 0xed3fe218) [ 15.985414] Stack: (0xed3ffc08 to 0xed400000) [ 15.989954] fc00: ee54ab00 c009928c c0a9e648 60000193 000032e4 ee169c00 [ 15.998478] fc20: ee169c64 ee169c00 ee169c64 ee54ab00 00000001 00000001 ee67e268 ee008800 [ 16.006995] fc40: ee534800 c009946c ee169c00 ee169c64 c08bd660 c009c370 c009c2a4 000000c6 [ 16.015513] fc60: c08b75c4 c08b0854 00000000 c0098b3c 000000c6 c0098c50 ed3ffcb0 0000003a [ 16.024033] fc80: ed3ffcb0 fa24010c c08b7800 fa240100 ee7e9880 c00094c4 c05ef4e8 60000013 [ 16.032556] fca0: ffffffff ed3ffce4 ee7e9880 c05ef964 00000001 ed2a33d8 00000000 ed2a2e00 [ 16.041080] fcc0: 60000013 ee536bf8 60000013 ee51b800 ee7e9880 ee67e268 ee7e9880 ee534800 [ 16.049603] fce0: c0ad0768 ed3ffcf8 c008e910 c05ef4e8 60000013 ffffffff 00000001 00000001 [ 16.058121] fd00: ee536bf8 c0487a04 00000000 00000000 ee534800 00000000 00000156 c048c990 [ 16.066645] fd20: 00000000 00000000 c0969f40 00000000 00000000 c05000e8 00000001 00000000 [ 16.075167] fd40: 00000000 c051eefc 00000000 ee67e268 00000000 00000000 ee51b800 ed3ffd9c [ 16.083690] fd60: 00000000 ee67e200 ee51b800 ee7e9880 ee67e268 00000000 00000000 ee67e200 [ 16.092211] fd80: ee51b800 ee7e9880 ee67e268 ee534800 ee67e200 c051eedc ee67e268 00000010 [ 16.100727] fda0: 00000000 00000000 ee7e9880 ee534800 00000000 ee67e268 ee51b800 c05006fc [ 16.109247] fdc0: ee67e268 00000001 c0500488 00000156 ee7e9880 00000000 ed3fe000 fffffff4 [ 16.117771] fde0: ed3fff1c ee7e9880 ee534800 00000148 00000000 ed1f8340 00000000 00000000 [ 16.126289] fe00: 00000000 c05a9054 00000000 00000000 00000156 c0ab62a8 00000010 ed3e7000 [ 16.134812] fe20: 00000000 00000008 edcfb700 ed3fff1c c0fb5f94 ed2a2e00 c0fb5f64 000005d8 [ 16.143336] fe40: c0a9b3b8 00000000 ed3e7070 00000000 00000000 00000000 00009f40 00000000 [ 16.151858] fe60: 00000000 00020022 00110008 00000000 00000000 43004400 00000000 ffffffff [ 16.160374] fe80: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 16.168898] fea0: edcfb700 bee5f380 00000014 00000000 ed3fe000 00000000 00004400 c04e2b64 [ 16.177415] fec0: 00000002 c04e3b00 ed3ffeec 00000001 0000011a 00000000 00000000 bee5f394 [ 16.185937] fee0: 00000148 ed3fff10 00000014 00000001 00000000 00000000 ed3ffee4 00000000 [ 16.194459] ff00: 00000000 00000000 00000000 c04e3664 00080011 00000002 06000000 ffffffff [ 16.202980] ff20: 0000ffff ffffffff 0000ffff c008dd54 ee5a6f08 ee636e80 c096972d c0089c14 [ 16.211499] ff40: 00000000 60000013 ee5a6f40 60000013 00000000 ee5a6f40 00000002 00000006 [ 16.220023] ff60: 00000000 edcfb700 00000001 ed2a2e00 c000f60c 00000001 0000011a c008ea34 [ 16.228540] ff80: 00000006 00000000 bee5f380 00000014 bee5f380 00000014 bee5f380 00000122 [ 16.237059] ffa0: c000f7c4 c000f5e0 bee5f380 00000014 00000006 bee5f394 00000148 00000000 [ 16.245581] ffc0: bee5f380 00000014 bee5f380 00000122 fffffd6e 00004300 00004800 00004400 [ 16.254104] ffe0: bee5f378 bee5f36c 000307ec b6f39044 40000010 00000006 ed36fa40 00000000 [ 16.262642] [] (cpsw_tx_interrupt) from [] (handle_irq_event_percpu+0x64/0x204) [ 16.272076] [] (handle_irq_event_percpu) from [] (handle_irq_event+0x40/0x64) [ 16.281330] [] (handle_irq_event) from [] (handle_fasteoi_irq+0xcc/0x1a8) [ 16.290220] [] (handle_fasteoi_irq) from [] (generic_handle_irq+0x20/0x30) [ 16.299197] [] (generic_handle_irq) from [] (__handle_domain_irq+0x64/0xdc) [ 16.308273] [] (__handle_domain_irq) from [] (gic_handle_irq+0x20/0x60) [ 16.316987] [] (gic_handle_irq) from [] (__irq_svc+0x44/0x5c) [ 16.324779] Exception stack(0xed3ffcb0 to 0xed3ffcf8) [ 16.330044] fca0: 00000001 ed2a33d8 00000000 ed2a2e00 [ 16.338567] fcc0: 60000013 ee536bf8 60000013 ee51b800 ee7e9880 ee67e268 ee7e9880 ee534800 [ 16.347090] fce0: c0ad0768 ed3ffcf8 c008e910 c05ef4e8 60000013 ffffffff [ 16.353987] [] (__irq_svc) from [] (_raw_spin_unlock_irqrestore+0x34/0x44) [ 16.362973] [] (_raw_spin_unlock_irqrestore) from [] (cpdma_check_free_tx_desc+0x60/0x6c) [ 16.373311] [] (cpdma_check_free_tx_desc) from [] (cpsw_ndo_start_xmit+0xb4/0x1ac) [ 16.383017] [] (cpsw_ndo_start_xmit) from [] (dev_hard_start_xmit+0x2a4/0x4c0) [ 16.392364] [] (dev_hard_start_xmit) from [] (sch_direct_xmit+0xf4/0x210) [ 16.401246] [] (sch_direct_xmit) from [] (__dev_queue_xmit+0x2ac/0x7bc) [ 16.409960] [] (__dev_queue_xmit) from [] (packet_sendmsg+0xc68/0xeb4) [ 16.418585] [] (packet_sendmsg) from [] (sock_sendmsg+0x14/0x24) [ 16.426663] [] (sock_sendmsg) from [] (SyS_sendto+0xb4/0xe0) [ 16.434377] [] (SyS_sendto) from [] (ret_fast_syscall+0x0/0x54) [ 16.442360] Code: e5943118 e593303c e3530000 0a000002 (e5930720) [ 16.448716] ---[ end trace a68159f094d85ba6 ]--- [ 16.453526] Kernel panic - not syncing: Fatal exception in interrupt [ 16.460149] ---[ end Kernel panic - not syncing: Fatal exception in interrupt Signed-off-by: Mugunthan V N Cc: # v3.8+ Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpsw.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 462820514fae..e778703880d3 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -509,9 +509,11 @@ static const struct cpsw_stats cpsw_gstrings_stats[] = { (func)(slave++, ##arg); \ } while (0) #define cpsw_get_slave_ndev(priv, __slave_no__) \ - (priv->slaves[__slave_no__].ndev) + ((__slave_no__ < priv->data.slaves) ? \ + priv->slaves[__slave_no__].ndev : NULL) #define cpsw_get_slave_priv(priv, __slave_no__) \ - ((priv->slaves[__slave_no__].ndev) ? \ + (((__slave_no__ < priv->data.slaves) && \ + (priv->slaves[__slave_no__].ndev)) ? \ netdev_priv(priv->slaves[__slave_no__].ndev) : NULL) \ #define cpsw_dual_emac_src_port_detect(status, priv, ndev, skb) \ -- cgit v1.2.3-70-g09d2 From 671b53eec2edcbfac3e53d02cf3d0c6d9ecc07de Mon Sep 17 00:00:00 2001 From: Shradha Shah Date: Wed, 8 Jul 2015 10:12:45 +0100 Subject: sfc: Ensure down_write(&filter_sem) and up_write() are matched before calling efx_net_open() This patch avoids the double up_write to filter_sem if efx_net_open() fails. Resolves: 2d432f20d27c1813a2746008e16dd6ce12a14dc1 Signed-off-by: Shradha Shah Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10_sriov.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/sfc/ef10_sriov.c b/drivers/net/ethernet/sfc/ef10_sriov.c index 7485f71b4e2f..3c17f274e802 100644 --- a/drivers/net/ethernet/sfc/ef10_sriov.c +++ b/drivers/net/ethernet/sfc/ef10_sriov.c @@ -598,21 +598,21 @@ int efx_ef10_sriov_set_vf_vlan(struct efx_nic *efx, int vf_i, u16 vlan, MC_CMD_VPORT_ALLOC_IN_VPORT_TYPE_NORMAL, vf->vlan, &vf->vport_id); if (rc) - goto reset_nic; + goto reset_nic_up_write; restore_mac: if (!is_zero_ether_addr(vf->mac)) { rc2 = efx_ef10_vport_add_mac(efx, vf->vport_id, vf->mac); if (rc2) { eth_zero_addr(vf->mac); - goto reset_nic; + goto reset_nic_up_write; } } restore_evb_port: rc2 = efx_ef10_evb_port_assign(efx, vf->vport_id, vf_i); if (rc2) - goto reset_nic; + goto reset_nic_up_write; else vf->vport_assigned = 1; @@ -620,14 +620,16 @@ restore_vadaptor: if (vf->efx) { rc2 = efx_ef10_vadaptor_alloc(vf->efx, EVB_PORT_ID_ASSIGNED); if (rc2) - goto reset_nic; + goto reset_nic_up_write; } restore_filters: if (vf->efx) { rc2 = vf->efx->type->filter_table_probe(vf->efx); if (rc2) - goto reset_nic; + goto reset_nic_up_write; + + up_write(&vf->efx->filter_sem); up_write(&vf->efx->filter_sem); @@ -639,9 +641,12 @@ restore_filters: } return rc; +reset_nic_up_write: + if (vf->efx) + up_write(&vf->efx->filter_sem); + reset_nic: if (vf->efx) { - up_write(&vf->efx->filter_sem); netif_err(efx, drv, efx->net_dev, "Failed to restore VF - scheduling reset.\n"); efx_schedule_reset(vf->efx, RESET_TYPE_DATAPATH); -- cgit v1.2.3-70-g09d2 From 0769636cb5b95665ebadcd1a41c46f331f5a397d Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Tue, 7 Jul 2015 14:02:18 -0400 Subject: vmxnet3: prevent receive getting out of sequence on napi poll vmxnet3's current napi path is built to count every rx descriptor we recieve, and use that as a count of the napi budget. That means its possible to return from a napi poll halfway through recieving a fragmented packet accross multiple dma descriptors. If that happens, the next napi poll will start with the descriptor ring in an improper state (e.g. the first descriptor we look at may have the end-of-packet bit set), which will cause a BUG halt in the driver. Fix the issue by only counting whole received packets in the napi poll and returning that value, rather than the descriptor count. Tested by the reporter and myself, successfully Signed-off-by: Neil Horman CC: Shreyas Bhatewara CC: "David S. Miller" Acked-by: Andy Gospodarek Signed-off-by: David S. Miller --- drivers/net/vmxnet3/vmxnet3_drv.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index da11bb5e9c7f..46f4caddccbe 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -1216,7 +1216,7 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq, static const u32 rxprod_reg[2] = { VMXNET3_REG_RXPROD, VMXNET3_REG_RXPROD2 }; - u32 num_rxd = 0; + u32 num_pkts = 0; bool skip_page_frags = false; struct Vmxnet3_RxCompDesc *rcd; struct vmxnet3_rx_ctx *ctx = &rq->rx_ctx; @@ -1235,13 +1235,12 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq, struct Vmxnet3_RxDesc *rxd; u32 idx, ring_idx; struct vmxnet3_cmd_ring *ring = NULL; - if (num_rxd >= quota) { + if (num_pkts >= quota) { /* we may stop even before we see the EOP desc of * the current pkt */ break; } - num_rxd++; BUG_ON(rcd->rqID != rq->qid && rcd->rqID != rq->qid2); idx = rcd->rxdIdx; ring_idx = rcd->rqID < adapter->num_rx_queues ? 0 : 1; @@ -1413,6 +1412,7 @@ not_lro: napi_gro_receive(&rq->napi, skb); ctx->skb = NULL; + num_pkts++; } rcd_done: @@ -1443,7 +1443,7 @@ rcd_done: &rq->comp_ring.base[rq->comp_ring.next2proc].rcd, &rxComp); } - return num_rxd; + return num_pkts; } -- cgit v1.2.3-70-g09d2 From 4eed4d8ff984abcb983ada5b3dbf56fce35f1068 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 7 Jul 2015 20:48:55 +0200 Subject: 3c59x: Fix shared IRQ handling As its first order of business, boomerang_interrupt() checks whether the device really has any pending interrupts. If it does not, it does nothing and returns, but it still returns IRQ_HANDLED. This is wrong: interrupt was not handled, IRQ handlers of other devices sharing this IRQ line need to be called. vortex_interrupt() has it right: it returns IRQ_NONE in this case via IRQ_RETVAL(0). Do the same in boomerang_interrupt(). Signed-off-by: Denys Vlasenko CC: David S. Miller CC: linux-kernel@vger.kernel.org CC: netdev@vger.kernel.org Signed-off-by: David S. Miller --- drivers/net/ethernet/3com/3c59x.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/3com/3c59x.c b/drivers/net/ethernet/3com/3c59x.c index 41095ebad97f..2d1ce3c5d0dd 100644 --- a/drivers/net/ethernet/3com/3c59x.c +++ b/drivers/net/ethernet/3com/3c59x.c @@ -2382,6 +2382,7 @@ boomerang_interrupt(int irq, void *dev_id) void __iomem *ioaddr; int status; int work_done = max_interrupt_work; + int handled = 0; ioaddr = vp->ioaddr; @@ -2400,6 +2401,7 @@ boomerang_interrupt(int irq, void *dev_id) if ((status & IntLatch) == 0) goto handler_exit; /* No interrupt: shared IRQs can cause this */ + handled = 1; if (status == 0xffff) { /* h/w no longer present (hotplug)? */ if (vortex_debug > 1) @@ -2501,7 +2503,7 @@ boomerang_interrupt(int irq, void *dev_id) handler_exit: vp->handling_irq = 0; spin_unlock(&vp->lock); - return IRQ_HANDLED; + return IRQ_RETVAL(handled); } static int vortex_rx(struct net_device *dev) -- cgit v1.2.3-70-g09d2 From d065c3c17dae95832badf6329512dd057c905890 Mon Sep 17 00:00:00 2001 From: Zheng Liu Date: Tue, 7 Jul 2015 13:54:12 -0700 Subject: drivers/net/usb: add device id for NVIDIA Tegra USB 3.0 Ethernet This device is sold as 'NVIDIA Tegra USB 3.0 Ethernet'. Chipset is RTL8153 and works with r8152. Signed-off-by: Zheng Liu Signed-off-by: David S. Miller --- drivers/net/usb/cdc_ether.c | 8 ++++++++ drivers/net/usb/r8152.c | 2 ++ 2 files changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index 4545e78840b0..35a2bffe848a 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -523,6 +523,7 @@ static const struct driver_info wwan_info = { #define REALTEK_VENDOR_ID 0x0bda #define SAMSUNG_VENDOR_ID 0x04e8 #define LENOVO_VENDOR_ID 0x17ef +#define NVIDIA_VENDOR_ID 0x0955 static const struct usb_device_id products[] = { /* BLACKLIST !! @@ -710,6 +711,13 @@ static const struct usb_device_id products[] = { .driver_info = 0, }, +/* NVIDIA Tegra USB 3.0 Ethernet Adapters (based on Realtek RTL8153) */ +{ + USB_DEVICE_AND_INTERFACE_INFO(NVIDIA_VENDOR_ID, 0x09ff, USB_CLASS_COMM, + USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), + .driver_info = 0, +}, + /* WHITELIST!!! * * CDC Ether uses two interfaces, not necessarily consecutive. diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index aafa1a1898e4..7f6419ebb5e1 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -494,6 +494,7 @@ enum rtl8152_flags { #define VENDOR_ID_REALTEK 0x0bda #define VENDOR_ID_SAMSUNG 0x04e8 #define VENDOR_ID_LENOVO 0x17ef +#define VENDOR_ID_NVIDIA 0x0955 #define MCU_TYPE_PLA 0x0100 #define MCU_TYPE_USB 0x0000 @@ -4117,6 +4118,7 @@ static struct usb_device_id rtl8152_table[] = { {REALTEK_USB_DEVICE(VENDOR_ID_SAMSUNG, 0xa101)}, {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x7205)}, {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x304f)}, + {REALTEK_USB_DEVICE(VENDOR_ID_NVIDIA, 0x09ff)}, {} }; -- cgit v1.2.3-70-g09d2 From c936835c1ec6f871f32c9b87a7708700320075b3 Mon Sep 17 00:00:00 2001 From: Peter Dunning Date: Wed, 8 Jul 2015 10:05:10 +0100 Subject: sfc: Report TX completions to BQL after all TX events in interrupt The limit for BQL is updated each time we call netdev_tx_completed_queue. Without this patch the BQL limit was updated for every TX event we see. The issue was that this only updated the limit to handle the data we complete in two events as the first event wouldn't show that enough traffic had been processed between them. This was OK when interrupt moderation was off but not when it was on as more data had to be completed in a single interrupt. The patch changes this so that we do report the completion to BQL only when all the TX events in the interrupt have been processed. Signed-off-by: Shradha Shah Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/efx.c | 14 ++++++++++++++ drivers/net/ethernet/sfc/net_driver.h | 2 ++ drivers/net/ethernet/sfc/tx.c | 3 ++- 3 files changed, 18 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 804b9ad553d3..03bc03b67f08 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -245,11 +245,17 @@ static int efx_check_disabled(struct efx_nic *efx) */ static int efx_process_channel(struct efx_channel *channel, int budget) { + struct efx_tx_queue *tx_queue; int spent; if (unlikely(!channel->enabled)) return 0; + efx_for_each_channel_tx_queue(tx_queue, channel) { + tx_queue->pkts_compl = 0; + tx_queue->bytes_compl = 0; + } + spent = efx_nic_process_eventq(channel, budget); if (spent && efx_channel_has_rx_queue(channel)) { struct efx_rx_queue *rx_queue = @@ -259,6 +265,14 @@ static int efx_process_channel(struct efx_channel *channel, int budget) efx_fast_push_rx_descriptors(rx_queue, true); } + /* Update BQL */ + efx_for_each_channel_tx_queue(tx_queue, channel) { + if (tx_queue->bytes_compl) { + netdev_tx_completed_queue(tx_queue->core_txq, + tx_queue->pkts_compl, tx_queue->bytes_compl); + } + } + return spent; } diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index d72f522bf9c3..47d1e3a96522 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -241,6 +241,8 @@ struct efx_tx_queue { unsigned int read_count ____cacheline_aligned_in_smp; unsigned int old_write_count; unsigned int merge_events; + unsigned int bytes_compl; + unsigned int pkts_compl; /* Members used only on the xmit path */ unsigned int insert_count ____cacheline_aligned_in_smp; diff --git a/drivers/net/ethernet/sfc/tx.c b/drivers/net/ethernet/sfc/tx.c index aaf2987512b5..1833a0146571 100644 --- a/drivers/net/ethernet/sfc/tx.c +++ b/drivers/net/ethernet/sfc/tx.c @@ -617,7 +617,8 @@ void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index) EFX_BUG_ON_PARANOID(index > tx_queue->ptr_mask); efx_dequeue_buffers(tx_queue, index, &pkts_compl, &bytes_compl); - netdev_tx_completed_queue(tx_queue->core_txq, pkts_compl, bytes_compl); + tx_queue->pkts_compl += pkts_compl; + tx_queue->bytes_compl += bytes_compl; if (pkts_compl > 1) ++tx_queue->merge_events; -- cgit v1.2.3-70-g09d2 From d5de1987853a7778bb048a9e52b3486eb9aceb17 Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Wed, 8 Jul 2015 17:16:49 +0200 Subject: macvtap: Destroy minor_idr on module_exit Destroy minor_idr on module_exit, reclaiming the allocated memory. This was detected by the following semantic patch (written by Luis Rodriguez ) @ defines_module_init @ declarer name module_init, module_exit; declarer name DEFINE_IDR; identifier init; @@ module_init(init); @ defines_module_exit @ identifier exit; @@ module_exit(exit); @ declares_idr depends on defines_module_init && defines_module_exit @ identifier idr; @@ DEFINE_IDR(idr); @ on_exit_calls_destroy depends on declares_idr && defines_module_exit @ identifier declares_idr.idr, defines_module_exit.exit; @@ exit(void) { ... idr_destroy(&idr); ... } @ missing_module_idr_destroy depends on declares_idr && defines_module_exit && !on_exit_calls_destroy @ identifier declares_idr.idr, defines_module_exit.exit; @@ exit(void) { ... +idr_destroy(&idr); } Signed-off-by: Johannes Thumshirn Signed-off-by: David S. Miller --- drivers/net/macvtap.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 6a64197f5bce..b4b61910f616 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -1294,6 +1294,7 @@ static void macvtap_exit(void) class_unregister(macvtap_class); cdev_del(&macvtap_cdev); unregister_chrdev_region(macvtap_major, MACVTAP_NUM_DEVS); + idr_destroy(&minor_idr); } module_exit(macvtap_exit); -- cgit v1.2.3-70-g09d2 From 19ee835cdb0b5a8eb11a68f25a51b8039d564488 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 29 Jun 2015 14:01:19 +0100 Subject: drm/i915: Declare the swizzling unknown for L-shaped configurations The old style of memory interleaving swizzled upto the end of the first even bank of memory, and then used the remainder as unswizzled on the unpaired bank - i.e. swizzling is not constant for all memory. This causes problems when we try to migrate memory and so the kernel prevents migration at all when we detect L-shaped inconsistent swizzling. However, this issue also extends to userspace who try to manually detile into memory as the swizzling for an individual page is unknown (it depends on its physical address only known to the kernel), userspace cannot correctly swizzle objects. v2: Mark the global swizzling as unknown rather than adjust the value reported to userspace. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=91105 Signed-off-by: Chris Wilson Cc: Daniel Vetter Cc: stable@vger.kernel.org Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_tiling.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index 633bd1fcab69..d61e74a08f82 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -183,8 +183,18 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev) if (IS_GEN4(dev)) { uint32_t ddc2 = I915_READ(DCC2); - if (!(ddc2 & DCC2_MODIFIED_ENHANCED_DISABLE)) + if (!(ddc2 & DCC2_MODIFIED_ENHANCED_DISABLE)) { + /* Since the swizzling may vary within an + * object, we have no idea what the swizzling + * is for any page in particular. Thus we + * cannot migrate tiled pages using the GPU, + * nor can we tell userspace what the exact + * swizzling is for any object. + */ dev_priv->quirks |= QUIRK_PIN_SWIZZLED_PAGES; + swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN; + swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN; + } } if (dcc == 0xffffffff) { -- cgit v1.2.3-70-g09d2 From 52613921b31d8573a212a4b0854b390a18d9849c Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 29 Jun 2015 20:28:35 +0300 Subject: Revert "drm/i915: Allocate context objects from stolen" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stolen gets trashed during hibernation, so storing contexts there is not a very good idea. On my IVB machines this leads to a totally dead GPU on resume. A reboot is required to resurrect it. So let's not store contexts where they will get trampled. This reverts commit 149c86e74fe44dcbac5e9f8d145c5fbc5dc21261. Cc: Chris Wilson Signed-off-by: Ville Syrjälä Acked-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 8867818b1401..d65cbe6afb92 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -157,9 +157,7 @@ i915_gem_alloc_context_obj(struct drm_device *dev, size_t size) struct drm_i915_gem_object *obj; int ret; - obj = i915_gem_object_create_stolen(dev, size); - if (obj == NULL) - obj = i915_gem_alloc_object(dev, size); + obj = i915_gem_alloc_object(dev, size); if (obj == NULL) return ERR_PTR(-ENOMEM); -- cgit v1.2.3-70-g09d2 From a0f67441b06525a1e5fd713ba0d75af4e5d6b198 Mon Sep 17 00:00:00 2001 From: Maninder Singh Date: Thu, 9 Jul 2015 14:41:53 +0530 Subject: drm/amdkfd: validate pdd where it acquired first Currently pdd is validate after dereferencing it, which is not correct, Thus validate pdd before its first use. Signed-off-by: Maninder Singh Signed-off-by: Oded Gabbay --- drivers/gpu/drm/amd/amdkfd/kfd_process.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c index 8a1f999daa24..9be007081b72 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c @@ -420,6 +420,12 @@ void kfd_unbind_process_from_device(struct kfd_dev *dev, unsigned int pasid) pqm_uninit(&p->pqm); pdd = kfd_get_process_device_data(dev, p); + + if (!pdd) { + mutex_unlock(&p->mutex); + return; + } + if (pdd->reset_wavefronts) { dbgdev_wave_reset_wavefronts(pdd->dev, p); pdd->reset_wavefronts = false; @@ -431,8 +437,7 @@ void kfd_unbind_process_from_device(struct kfd_dev *dev, unsigned int pasid) * We don't call amd_iommu_unbind_pasid() here * because the IOMMU called us. */ - if (pdd) - pdd->bound = false; + pdd->bound = false; mutex_unlock(&p->mutex); } -- cgit v1.2.3-70-g09d2 From cd404af0c930104462aa91344f07d002cf8248ed Mon Sep 17 00:00:00 2001 From: Michel Dänzer Date: Tue, 7 Jul 2015 16:27:28 +0900 Subject: drm/radeon: Clean up reference counting and pinning of the cursor BOs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Take a GEM reference for and pin the new cursor BO, unpin and drop the GEM reference for the old cursor BO in radeon_crtc_cursor_set2, and use radeon_crtc->cursor_addr in radeon_set_cursor. This fixes radeon_cursor_reset accidentally incrementing the cursor BO pin count, and cleans up the code a little. Cc: stable@vger.kernel.org Reviewed-by: Grigori Goronzy Reviewed-by: Christian König Signed-off-by: Michel Dänzer Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_cursor.c | 84 +++++++++++++++------------------- drivers/gpu/drm/radeon/radeon_mode.h | 1 - 2 files changed, 37 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c index 45e54060ee97..fa661744a1f5 100644 --- a/drivers/gpu/drm/radeon/radeon_cursor.c +++ b/drivers/gpu/drm/radeon/radeon_cursor.c @@ -205,8 +205,9 @@ static int radeon_cursor_move_locked(struct drm_crtc *crtc, int x, int y) | (x << 16) | y)); /* offset is from DISP(2)_BASE_ADDRESS */ - WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, (radeon_crtc->legacy_cursor_offset + - (yorigin * 256))); + WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, + radeon_crtc->cursor_addr - radeon_crtc->legacy_display_base_addr + + yorigin * 256); } radeon_crtc->cursor_x = x; @@ -227,51 +228,32 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc, return ret; } -static int radeon_set_cursor(struct drm_crtc *crtc, struct drm_gem_object *obj) +static void radeon_set_cursor(struct drm_crtc *crtc) { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct radeon_device *rdev = crtc->dev->dev_private; - struct radeon_bo *robj = gem_to_radeon_bo(obj); - uint64_t gpu_addr; - int ret; - - ret = radeon_bo_reserve(robj, false); - if (unlikely(ret != 0)) - goto fail; - /* Only 27 bit offset for legacy cursor */ - ret = radeon_bo_pin_restricted(robj, RADEON_GEM_DOMAIN_VRAM, - ASIC_IS_AVIVO(rdev) ? 0 : 1 << 27, - &gpu_addr); - radeon_bo_unreserve(robj); - if (ret) - goto fail; if (ASIC_IS_DCE4(rdev)) { WREG32(EVERGREEN_CUR_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, - upper_32_bits(gpu_addr)); + upper_32_bits(radeon_crtc->cursor_addr)); WREG32(EVERGREEN_CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset, - gpu_addr & 0xffffffff); + lower_32_bits(radeon_crtc->cursor_addr)); } else if (ASIC_IS_AVIVO(rdev)) { if (rdev->family >= CHIP_RV770) { if (radeon_crtc->crtc_id) - WREG32(R700_D2CUR_SURFACE_ADDRESS_HIGH, upper_32_bits(gpu_addr)); + WREG32(R700_D2CUR_SURFACE_ADDRESS_HIGH, + upper_32_bits(radeon_crtc->cursor_addr)); else - WREG32(R700_D1CUR_SURFACE_ADDRESS_HIGH, upper_32_bits(gpu_addr)); + WREG32(R700_D1CUR_SURFACE_ADDRESS_HIGH, + upper_32_bits(radeon_crtc->cursor_addr)); } WREG32(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset, - gpu_addr & 0xffffffff); + lower_32_bits(radeon_crtc->cursor_addr)); } else { - radeon_crtc->legacy_cursor_offset = gpu_addr - radeon_crtc->legacy_display_base_addr; /* offset is from DISP(2)_BASE_ADDRESS */ - WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, radeon_crtc->legacy_cursor_offset); + WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, + radeon_crtc->cursor_addr - radeon_crtc->legacy_display_base_addr); } - - return 0; - -fail: - drm_gem_object_unreference_unlocked(obj); - - return ret; } int radeon_crtc_cursor_set2(struct drm_crtc *crtc, @@ -283,7 +265,9 @@ int radeon_crtc_cursor_set2(struct drm_crtc *crtc, int32_t hot_y) { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct radeon_device *rdev = crtc->dev->dev_private; struct drm_gem_object *obj; + struct radeon_bo *robj; int ret; if (!handle) { @@ -305,6 +289,23 @@ int radeon_crtc_cursor_set2(struct drm_crtc *crtc, return -ENOENT; } + robj = gem_to_radeon_bo(obj); + ret = radeon_bo_reserve(robj, false); + if (ret != 0) { + drm_gem_object_unreference_unlocked(obj); + return ret; + } + /* Only 27 bit offset for legacy cursor */ + ret = radeon_bo_pin_restricted(robj, RADEON_GEM_DOMAIN_VRAM, + ASIC_IS_AVIVO(rdev) ? 0 : 1 << 27, + &radeon_crtc->cursor_addr); + radeon_bo_unreserve(robj); + if (ret) { + DRM_ERROR("Failed to pin new cursor BO (%d)\n", ret); + drm_gem_object_unreference_unlocked(obj); + return ret; + } + radeon_crtc->cursor_width = width; radeon_crtc->cursor_height = height; @@ -323,13 +324,8 @@ int radeon_crtc_cursor_set2(struct drm_crtc *crtc, radeon_crtc->cursor_hot_y = hot_y; } - ret = radeon_set_cursor(crtc, obj); - - if (ret) - DRM_ERROR("radeon_set_cursor returned %d, not changing cursor\n", - ret); - else - radeon_show_cursor(crtc); + radeon_set_cursor(crtc); + radeon_show_cursor(crtc); radeon_lock_cursor(crtc, false); @@ -341,8 +337,7 @@ unpin: radeon_bo_unpin(robj); radeon_bo_unreserve(robj); } - if (radeon_crtc->cursor_bo != obj) - drm_gem_object_unreference_unlocked(radeon_crtc->cursor_bo); + drm_gem_object_unreference_unlocked(radeon_crtc->cursor_bo); } radeon_crtc->cursor_bo = obj; @@ -360,7 +355,6 @@ unpin: void radeon_cursor_reset(struct drm_crtc *crtc) { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); - int ret; if (radeon_crtc->cursor_bo) { radeon_lock_cursor(crtc, true); @@ -368,12 +362,8 @@ void radeon_cursor_reset(struct drm_crtc *crtc) radeon_cursor_move_locked(crtc, radeon_crtc->cursor_x, radeon_crtc->cursor_y); - ret = radeon_set_cursor(crtc, radeon_crtc->cursor_bo); - if (ret) - DRM_ERROR("radeon_set_cursor returned %d, not showing " - "cursor\n", ret); - else - radeon_show_cursor(crtc); + radeon_set_cursor(crtc); + radeon_show_cursor(crtc); radeon_lock_cursor(crtc, false); } diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 6de5459316b5..07909d817381 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -343,7 +343,6 @@ struct radeon_crtc { int max_cursor_width; int max_cursor_height; uint32_t legacy_display_base_addr; - uint32_t legacy_cursor_offset; enum radeon_rmx_type rmx_type; u8 h_border; u8 v_border; -- cgit v1.2.3-70-g09d2 From f3cbb17bcf676a2fc6aedebe9fbebd59e550c51a Mon Sep 17 00:00:00 2001 From: Grigori Goronzy Date: Tue, 7 Jul 2015 16:27:29 +0900 Subject: drm/radeon: unpin cursor BOs on suspend and pin them again on resume (v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Everything is evicted from VRAM before suspend, so we need to make sure all BOs are unpinned and re-pinned after resume. Fixes broken mouse cursor after resume introduced by commit b9729b17. [Michel Dänzer: Add pinning BOs on resume] v2: [Alex Deucher: merge cursor unpin into fb unpin loop] Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=100541 Cc: stable@vger.kernel.org Reviewed-by: Christian König (v1) Signed-off-by: Grigori Goronzy Signed-off-by: Michel Dänzer Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_device.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 1a532a9bc3a3..d8319dae8358 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -1578,11 +1578,21 @@ int radeon_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon) drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); } - /* unpin the front buffers */ + /* unpin the front buffers and cursors */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct radeon_framebuffer *rfb = to_radeon_framebuffer(crtc->primary->fb); struct radeon_bo *robj; + if (radeon_crtc->cursor_bo) { + struct radeon_bo *robj = gem_to_radeon_bo(radeon_crtc->cursor_bo); + r = radeon_bo_reserve(robj, false); + if (r == 0) { + radeon_bo_unpin(robj); + radeon_bo_unreserve(robj); + } + } + if (rfb == NULL || rfb->obj == NULL) { continue; } @@ -1645,6 +1655,7 @@ int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon) { struct drm_connector *connector; struct radeon_device *rdev = dev->dev_private; + struct drm_crtc *crtc; int r; if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) @@ -1684,6 +1695,27 @@ int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon) radeon_restore_bios_scratch_regs(rdev); + /* pin cursors */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + + if (radeon_crtc->cursor_bo) { + struct radeon_bo *robj = gem_to_radeon_bo(radeon_crtc->cursor_bo); + r = radeon_bo_reserve(robj, false); + if (r == 0) { + /* Only 27 bit offset for legacy cursor */ + r = radeon_bo_pin_restricted(robj, + RADEON_GEM_DOMAIN_VRAM, + ASIC_IS_AVIVO(rdev) ? + 0 : 1 << 27, + &radeon_crtc->cursor_addr); + if (r != 0) + DRM_ERROR("Failed to pin cursor BO (%d)\n", r); + radeon_bo_unreserve(robj); + } + } + } + /* init dig PHYs, disp eng pll */ if (rdev->is_atom_bios) { radeon_atom_encoder_init(rdev); -- cgit v1.2.3-70-g09d2 From 8991668ab4e26f985a8485719bce5d6d0623a644 Mon Sep 17 00:00:00 2001 From: Michel Dänzer Date: Tue, 7 Jul 2015 16:27:30 +0900 Subject: drm/radeon: Fold radeon_set_cursor() into radeon_show_cursor() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Grigori Goronzy Reviewed-by: Christian König Signed-off-by: Michel Dänzer Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_cursor.c | 49 +++++++++++++--------------------- 1 file changed, 19 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c index fa661744a1f5..afaf346bd50e 100644 --- a/drivers/gpu/drm/radeon/radeon_cursor.c +++ b/drivers/gpu/drm/radeon/radeon_cursor.c @@ -91,15 +91,34 @@ static void radeon_show_cursor(struct drm_crtc *crtc) struct radeon_device *rdev = crtc->dev->dev_private; if (ASIC_IS_DCE4(rdev)) { + WREG32(EVERGREEN_CUR_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, + upper_32_bits(radeon_crtc->cursor_addr)); + WREG32(EVERGREEN_CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset, + lower_32_bits(radeon_crtc->cursor_addr)); WREG32(RADEON_MM_INDEX, EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset); WREG32(RADEON_MM_DATA, EVERGREEN_CURSOR_EN | EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT) | EVERGREEN_CURSOR_URGENT_CONTROL(EVERGREEN_CURSOR_URGENT_1_2)); } else if (ASIC_IS_AVIVO(rdev)) { + if (rdev->family >= CHIP_RV770) { + if (radeon_crtc->crtc_id) + WREG32(R700_D2CUR_SURFACE_ADDRESS_HIGH, + upper_32_bits(radeon_crtc->cursor_addr)); + else + WREG32(R700_D1CUR_SURFACE_ADDRESS_HIGH, + upper_32_bits(radeon_crtc->cursor_addr)); + } + + WREG32(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset, + lower_32_bits(radeon_crtc->cursor_addr)); WREG32(RADEON_MM_INDEX, AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset); WREG32(RADEON_MM_DATA, AVIVO_D1CURSOR_EN | (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT)); } else { + /* offset is from DISP(2)_BASE_ADDRESS */ + WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, + radeon_crtc->cursor_addr - radeon_crtc->legacy_display_base_addr); + switch (radeon_crtc->crtc_id) { case 0: WREG32(RADEON_MM_INDEX, RADEON_CRTC_GEN_CNTL); @@ -228,34 +247,6 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc, return ret; } -static void radeon_set_cursor(struct drm_crtc *crtc) -{ - struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); - struct radeon_device *rdev = crtc->dev->dev_private; - - if (ASIC_IS_DCE4(rdev)) { - WREG32(EVERGREEN_CUR_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, - upper_32_bits(radeon_crtc->cursor_addr)); - WREG32(EVERGREEN_CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset, - lower_32_bits(radeon_crtc->cursor_addr)); - } else if (ASIC_IS_AVIVO(rdev)) { - if (rdev->family >= CHIP_RV770) { - if (radeon_crtc->crtc_id) - WREG32(R700_D2CUR_SURFACE_ADDRESS_HIGH, - upper_32_bits(radeon_crtc->cursor_addr)); - else - WREG32(R700_D1CUR_SURFACE_ADDRESS_HIGH, - upper_32_bits(radeon_crtc->cursor_addr)); - } - WREG32(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset, - lower_32_bits(radeon_crtc->cursor_addr)); - } else { - /* offset is from DISP(2)_BASE_ADDRESS */ - WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, - radeon_crtc->cursor_addr - radeon_crtc->legacy_display_base_addr); - } -} - int radeon_crtc_cursor_set2(struct drm_crtc *crtc, struct drm_file *file_priv, uint32_t handle, @@ -324,7 +315,6 @@ int radeon_crtc_cursor_set2(struct drm_crtc *crtc, radeon_crtc->cursor_hot_y = hot_y; } - radeon_set_cursor(crtc); radeon_show_cursor(crtc); radeon_lock_cursor(crtc, false); @@ -362,7 +352,6 @@ void radeon_cursor_reset(struct drm_crtc *crtc) radeon_cursor_move_locked(crtc, radeon_crtc->cursor_x, radeon_crtc->cursor_y); - radeon_set_cursor(crtc); radeon_show_cursor(crtc); radeon_lock_cursor(crtc, false); -- cgit v1.2.3-70-g09d2 From d57c0edfe00d3274b50f91ce3076ed0e82d28782 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 8 Jul 2015 14:08:12 -0400 Subject: Revert "Revert "drm/radeon: dont switch vt on suspend"" This reverts commit ac9134906b3f5c2b45dc80dab0fee792bd516d52. We've fixed the underlying problem with cursors, so re-enable this. --- drivers/gpu/drm/radeon/radeon_fb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index 634793ea8418..aeb676708e60 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -257,6 +257,7 @@ static int radeonfb_create(struct drm_fb_helper *helper, } info->par = rfbdev; + info->skip_vt_switch = true; ret = radeon_framebuffer_init(rdev->ddev, &rfbdev->rfb, &mode_cmd, gobj); if (ret) { -- cgit v1.2.3-70-g09d2 From eb99070b4ad105f8a516d99e95226180924eddc8 Mon Sep 17 00:00:00 2001 From: Christian König Date: Wed, 8 Jul 2015 09:56:13 +0200 Subject: drm/radeon: allways add the VM clear duplicate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need to allways add the VM clear duplicate of the BO_VA, no matter what the old status was. Signed-off-by: Christian König Test-by: hadack@gmx.de Tested-by: Michel Dänzer Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_vm.c | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_vm.c b/drivers/gpu/drm/radeon/radeon_vm.c index ec10533a49b8..031096599f84 100644 --- a/drivers/gpu/drm/radeon/radeon_vm.c +++ b/drivers/gpu/drm/radeon/radeon_vm.c @@ -493,29 +493,27 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev, } if (bo_va->it.start || bo_va->it.last) { - spin_lock(&vm->status_lock); - if (list_empty(&bo_va->vm_status)) { - /* add a clone of the bo_va to clear the old address */ - struct radeon_bo_va *tmp; - spin_unlock(&vm->status_lock); - tmp = kzalloc(sizeof(struct radeon_bo_va), GFP_KERNEL); - if (!tmp) { - mutex_unlock(&vm->mutex); - r = -ENOMEM; - goto error_unreserve; - } - tmp->it.start = bo_va->it.start; - tmp->it.last = bo_va->it.last; - tmp->vm = vm; - tmp->bo = radeon_bo_ref(bo_va->bo); - spin_lock(&vm->status_lock); - list_add(&tmp->vm_status, &vm->freed); + /* add a clone of the bo_va to clear the old address */ + struct radeon_bo_va *tmp; + tmp = kzalloc(sizeof(struct radeon_bo_va), GFP_KERNEL); + if (!tmp) { + mutex_unlock(&vm->mutex); + r = -ENOMEM; + goto error_unreserve; } - spin_unlock(&vm->status_lock); + tmp->it.start = bo_va->it.start; + tmp->it.last = bo_va->it.last; + tmp->vm = vm; + tmp->bo = radeon_bo_ref(bo_va->bo); interval_tree_remove(&bo_va->it, &vm->va); bo_va->it.start = 0; bo_va->it.last = 0; + + spin_lock(&vm->status_lock); + list_del_init(&bo_va->vm_status); + list_add(&tmp->vm_status, &vm->freed); + spin_unlock(&vm->status_lock); } if (soffset || eoffset) { -- cgit v1.2.3-70-g09d2 From dbedff05d163f8d1b4a97b91c57b939830fc235f Mon Sep 17 00:00:00 2001 From: Christian König Date: Wed, 8 Jul 2015 09:56:14 +0200 Subject: drm/radeon: check if BO_VA is set before adding it to the invalidation list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Otherwise we try to clear BO_VAs without an address. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=91141 Signed-off-by: Christian König Test-by: hadack@gmx.de Tested-by: Michel Dänzer Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_vm.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_vm.c b/drivers/gpu/drm/radeon/radeon_vm.c index 031096599f84..48d97c040f49 100644 --- a/drivers/gpu/drm/radeon/radeon_vm.c +++ b/drivers/gpu/drm/radeon/radeon_vm.c @@ -507,22 +507,21 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev, tmp->bo = radeon_bo_ref(bo_va->bo); interval_tree_remove(&bo_va->it, &vm->va); + spin_lock(&vm->status_lock); bo_va->it.start = 0; bo_va->it.last = 0; - - spin_lock(&vm->status_lock); list_del_init(&bo_va->vm_status); list_add(&tmp->vm_status, &vm->freed); spin_unlock(&vm->status_lock); } if (soffset || eoffset) { + spin_lock(&vm->status_lock); bo_va->it.start = soffset; bo_va->it.last = eoffset - 1; - interval_tree_insert(&bo_va->it, &vm->va); - spin_lock(&vm->status_lock); list_add(&bo_va->vm_status, &vm->cleared); spin_unlock(&vm->status_lock); + interval_tree_insert(&bo_va->it, &vm->va); } bo_va->flags = flags; @@ -1156,7 +1155,8 @@ void radeon_vm_bo_invalidate(struct radeon_device *rdev, list_for_each_entry(bo_va, &bo->va, bo_list) { spin_lock(&bo_va->vm->status_lock); - if (list_empty(&bo_va->vm_status)) + if (list_empty(&bo_va->vm_status) && + (bo_va->it.start || bo_va->it.last)) list_add(&bo_va->vm_status, &bo_va->vm->invalidated); spin_unlock(&bo_va->vm->status_lock); } -- cgit v1.2.3-70-g09d2 From 0f11770417d849558c727ed20e1cd07444e15a00 Mon Sep 17 00:00:00 2001 From: Christian König Date: Wed, 8 Jul 2015 16:58:48 +0200 Subject: drm/amdgpu: fix timeout calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König Reviewed-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index 975edb1000a2..ae43b58c9733 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -352,7 +352,7 @@ unsigned long amdgpu_gem_timeout(uint64_t timeout_ns) if (((int64_t)timeout_ns) < 0) return MAX_SCHEDULE_TIMEOUT; - timeout = ktime_sub_ns(ktime_get(), timeout_ns); + timeout = ktime_sub(ns_to_ktime(timeout_ns), ktime_get()); if (ktime_to_ns(timeout) < 0) return 0; -- cgit v1.2.3-70-g09d2 From 355c822847fa70fa1df6a7451b7ecf76116efcd2 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 8 Jul 2015 12:58:20 -0400 Subject: drm/radeon: disable vce init on cayman (v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cayman does not have vce. There were a few places in the shared cayman/TV code where we were trying to do vce stuff. v2: remove -ENOENT check Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/ni.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index 8e5aeeb058a5..158872eb78e4 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -2162,18 +2162,20 @@ static int cayman_startup(struct radeon_device *rdev) DRM_ERROR("radeon: failed initializing UVD (%d).\n", r); } - ring = &rdev->ring[TN_RING_TYPE_VCE1_INDEX]; - if (ring->ring_size) - r = radeon_ring_init(rdev, ring, ring->ring_size, 0, 0x0); + if (rdev->family == CHIP_ARUBA) { + ring = &rdev->ring[TN_RING_TYPE_VCE1_INDEX]; + if (ring->ring_size) + r = radeon_ring_init(rdev, ring, ring->ring_size, 0, 0x0); - ring = &rdev->ring[TN_RING_TYPE_VCE2_INDEX]; - if (ring->ring_size) - r = radeon_ring_init(rdev, ring, ring->ring_size, 0, 0x0); + ring = &rdev->ring[TN_RING_TYPE_VCE2_INDEX]; + if (ring->ring_size) + r = radeon_ring_init(rdev, ring, ring->ring_size, 0, 0x0); - if (!r) - r = vce_v1_0_init(rdev); - else if (r != -ENOENT) - DRM_ERROR("radeon: failed initializing VCE (%d).\n", r); + if (!r) + r = vce_v1_0_init(rdev); + if (r) + DRM_ERROR("radeon: failed initializing VCE (%d).\n", r); + } r = radeon_ib_pool_init(rdev); if (r) { @@ -2396,7 +2398,8 @@ void cayman_fini(struct radeon_device *rdev) radeon_irq_kms_fini(rdev); uvd_v1_0_fini(rdev); radeon_uvd_fini(rdev); - radeon_vce_fini(rdev); + if (rdev->family == CHIP_ARUBA) + radeon_vce_fini(rdev); cayman_pcie_gart_fini(rdev); r600_vram_scratch_fini(rdev); radeon_gem_fini(rdev); -- cgit v1.2.3-70-g09d2 From 6f957724b94cb19f5c1c97efd01dd4df8ced323c Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 9 Jul 2015 11:20:01 -0700 Subject: Fix firmware loader uevent buffer NULL pointer dereference The firmware class uevent function accessed the "fw_priv->buf" buffer without the proper locking and testing for NULL. This is an old bug (looks like it goes back to 2012 and commit 1244691c73b2: "firmware loader: introduce firmware_buf"), but for some reason it's triggering only now in 4.2-rc1. Shuah Khan is trying to bisect what it is that causes this to trigger more easily, but in the meantime let's just fix the bug since others are hitting it too (at least Ingo reports having seen it as well). Reported-and-tested-by: Shuah Khan Acked-by: Ming Lei Cc: Greg Kroah-Hartman Signed-off-by: Linus Torvalds --- drivers/base/firmware_class.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 9c4288362a8e..894bda114224 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -563,10 +563,8 @@ static void fw_dev_release(struct device *dev) kfree(fw_priv); } -static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env) +static int do_firmware_uevent(struct firmware_priv *fw_priv, struct kobj_uevent_env *env) { - struct firmware_priv *fw_priv = to_firmware_priv(dev); - if (add_uevent_var(env, "FIRMWARE=%s", fw_priv->buf->fw_id)) return -ENOMEM; if (add_uevent_var(env, "TIMEOUT=%i", loading_timeout)) @@ -577,6 +575,18 @@ static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env) return 0; } +static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + struct firmware_priv *fw_priv = to_firmware_priv(dev); + int err = 0; + + mutex_lock(&fw_lock); + if (fw_priv->buf) + err = do_firmware_uevent(fw_priv, env); + mutex_unlock(&fw_lock); + return err; +} + static struct class firmware_class = { .name = "firmware", .class_attrs = firmware_class_attrs, -- cgit v1.2.3-70-g09d2 From fc0a1f035cf15f704f4092da294963c57e94c1c0 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 26 Jun 2015 14:12:10 +0200 Subject: i2c: I2C_MT65XX should depend on HAS_DMA If NO_DMA=y: ERROR: "dma_unmap_single" [drivers/i2c/busses/i2c-mt65xx.ko] undefined! ERROR: "dma_mapping_error" [drivers/i2c/busses/i2c-mt65xx.ko] undefined! ERROR: "dma_map_single" [drivers/i2c/busses/i2c-mt65xx.ko] undefined! Add a dependency on HAS_DMA to fix this. Signed-off-by: Geert Uytterhoeven Signed-off-by: Wolfram Sang --- drivers/i2c/busses/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 35ac23768ce9..577d58d1f1a1 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -633,6 +633,7 @@ config I2C_MPC config I2C_MT65XX tristate "MediaTek I2C adapter" depends on ARCH_MEDIATEK || COMPILE_TEST + depends on HAS_DMA help This selects the MediaTek(R) Integrated Inter Circuit bus driver for MT65xx and MT81xx. -- cgit v1.2.3-70-g09d2 From 724948106ed236fc528c720ae12c79af7e2aea4e Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 30 Jun 2015 11:08:46 +0800 Subject: i2c: xgene-slimpro: Fix missing mbox_free_channel call in probe error path Free requested mailbox channel before return error. Signed-off-by: Axel Lin Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-xgene-slimpro.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-xgene-slimpro.c b/drivers/i2c/busses/i2c-xgene-slimpro.c index dcca7076231e..1c9cb65ac4cf 100644 --- a/drivers/i2c/busses/i2c-xgene-slimpro.c +++ b/drivers/i2c/busses/i2c-xgene-slimpro.c @@ -419,6 +419,7 @@ static int xgene_slimpro_i2c_probe(struct platform_device *pdev) rc = i2c_add_adapter(adapter); if (rc) { dev_err(&pdev->dev, "Adapter registeration failed\n"); + mbox_free_channel(ctx->mbox_chan); return rc; } -- cgit v1.2.3-70-g09d2 From eb8173e3d7b94664ecd3acf34942c9c9d6f6cb73 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 30 Jun 2015 11:41:58 +0800 Subject: i2c: jz4780: Fix return value if probe fails Current code returns 0 if fails to read clock-frequency DT property, fix it. Also add checking return value of clk_prepare_enable and propagate return value of devm_request_irq. Signed-off-by: Axel Lin Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-jz4780.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-jz4780.c b/drivers/i2c/busses/i2c-jz4780.c index 19b2d689a5ef..f325663c27c5 100644 --- a/drivers/i2c/busses/i2c-jz4780.c +++ b/drivers/i2c/busses/i2c-jz4780.c @@ -764,12 +764,15 @@ static int jz4780_i2c_probe(struct platform_device *pdev) if (IS_ERR(i2c->clk)) return PTR_ERR(i2c->clk); - clk_prepare_enable(i2c->clk); + ret = clk_prepare_enable(i2c->clk); + if (ret) + return ret; - if (of_property_read_u32(pdev->dev.of_node, "clock-frequency", - &clk_freq)) { + ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency", + &clk_freq); + if (ret) { dev_err(&pdev->dev, "clock-frequency not specified in DT"); - return clk_freq; + goto err; } i2c->speed = clk_freq / 1000; @@ -790,10 +793,8 @@ static int jz4780_i2c_probe(struct platform_device *pdev) i2c->irq = platform_get_irq(pdev, 0); ret = devm_request_irq(&pdev->dev, i2c->irq, jz4780_i2c_irq, 0, dev_name(&pdev->dev), i2c); - if (ret) { - ret = -ENODEV; + if (ret) goto err; - } ret = i2c_add_adapter(&i2c->adap); if (ret < 0) { -- cgit v1.2.3-70-g09d2 From 4f001fd30145a6a8f72f9544c982cfd3dcb7c6df Mon Sep 17 00:00:00 2001 From: Pantelis Antoniou Date: Sat, 24 Jan 2015 09:16:29 +0200 Subject: i2c: Mark instantiated device nodes with OF_POPULATE Mark (and unmark) device nodes with the POPULATE flag as appropriate. This is required to avoid multi probing when using I2C and device overlays containing a mux. This patch is also more careful with the release of the adapter device which caused a deadlock with muxes, and does not break the build on !OF since the node flag accessors are not defined then. Signed-off-by: Pantelis Antoniou Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 069a41f116dd..e6d4935161e4 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1012,6 +1012,8 @@ EXPORT_SYMBOL_GPL(i2c_new_device); */ void i2c_unregister_device(struct i2c_client *client) { + if (client->dev.of_node) + of_node_clear_flag(client->dev.of_node, OF_POPULATED); device_unregister(&client->dev); } EXPORT_SYMBOL_GPL(i2c_unregister_device); @@ -1320,8 +1322,11 @@ static void of_i2c_register_devices(struct i2c_adapter *adap) dev_dbg(&adap->dev, "of_i2c: walking child nodes\n"); - for_each_available_child_of_node(adap->dev.of_node, node) + for_each_available_child_of_node(adap->dev.of_node, node) { + if (of_node_test_and_set_flag(node, OF_POPULATED)) + continue; of_i2c_register_device(adap, node); + } } static int of_dev_node_match(struct device *dev, void *data) @@ -1853,6 +1858,11 @@ static int of_i2c_notify(struct notifier_block *nb, unsigned long action, if (adap == NULL) return NOTIFY_OK; /* not for us */ + if (of_node_test_and_set_flag(rd->dn, OF_POPULATED)) { + put_device(&adap->dev); + return NOTIFY_OK; + } + client = of_i2c_register_device(adap, rd->dn); put_device(&adap->dev); @@ -1863,6 +1873,10 @@ static int of_i2c_notify(struct notifier_block *nb, unsigned long action, } break; case OF_RECONFIG_CHANGE_REMOVE: + /* already depopulated? */ + if (!of_node_check_flag(rd->dn, OF_POPULATED)) + return NOTIFY_OK; + /* find our device by node */ client = of_find_i2c_device_by_node(rd->dn); if (client == NULL) -- cgit v1.2.3-70-g09d2 From adb3505086def6d3e37013ec6cf8313cc719cbb6 Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Wed, 8 Jul 2015 10:49:30 +0530 Subject: net: systemport: Use eth_hw_addr_random Use eth_hw_addr_random() instead of calling random_ether_addr(). Here, this change is setting addr_assign_type to NET_ADDR_RANDOM. The Coccinelle semantic patch that performs this transformation is as follows: @@ identifier a,b; @@ -random_ether_addr(a->b); +eth_hw_addr_random(a); Signed-off-by: Vaishali Thakkar Tested-by: Florian Fainelli Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bcmsysport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c index 909ad7a0d480..4566cdf0bc39 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c @@ -1793,7 +1793,7 @@ static int bcm_sysport_probe(struct platform_device *pdev) macaddr = of_get_mac_address(dn); if (!macaddr || !is_valid_ether_addr(macaddr)) { dev_warn(&pdev->dev, "using random Ethernet MAC\n"); - random_ether_addr(dev->dev_addr); + eth_hw_addr_random(dev); } else { ether_addr_copy(dev->dev_addr, macaddr); } -- cgit v1.2.3-70-g09d2 From 5a0266af10246c84a6c712f365788800c7e23fd4 Mon Sep 17 00:00:00 2001 From: Mugunthan V N Date: Wed, 8 Jul 2015 14:35:22 +0530 Subject: drivers: net: cpsw: fix disabling of tx interrupt in rx isr In commit 'c03abd84634d ("net: ethernet: cpsw: don't requests IRQs we don't use")', common isr is split into tx and rx, but in rx isr tx interrupt is also disabledi in cpsw_disable_irq(). So tx interrupts are not handled during rx interrupts and rx napi completion and results in poor tx performance by 40Mbps. Fixing by disabling only rx interrupt in rx isr. Cc: Felipe Balbi Cc: # v4.0+ Signed-off-by: Mugunthan V N Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpsw.c | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index e778703880d3..f335bf119ab5 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -138,19 +138,6 @@ do { \ #define CPSW_CMINTMAX_INTVL (1000 / CPSW_CMINTMIN_CNT) #define CPSW_CMINTMIN_INTVL ((1000 / CPSW_CMINTMAX_CNT) + 1) -#define cpsw_enable_irq(priv) \ - do { \ - u32 i; \ - for (i = 0; i < priv->num_irqs; i++) \ - enable_irq(priv->irqs_table[i]); \ - } while (0) -#define cpsw_disable_irq(priv) \ - do { \ - u32 i; \ - for (i = 0; i < priv->num_irqs; i++) \ - disable_irq_nosync(priv->irqs_table[i]); \ - } while (0) - #define cpsw_slave_index(priv) \ ((priv->data.dual_emac) ? priv->emac_port : \ priv->data.active_slave) @@ -783,7 +770,7 @@ static irqreturn_t cpsw_rx_interrupt(int irq, void *dev_id) cpsw_intr_disable(priv); if (priv->irq_enabled == true) { - cpsw_disable_irq(priv); + disable_irq_nosync(priv->irqs_table[0]); priv->irq_enabled = false; } @@ -819,7 +806,7 @@ static int cpsw_poll(struct napi_struct *napi, int budget) prim_cpsw = cpsw_get_slave_priv(priv, 0); if (prim_cpsw->irq_enabled == false) { prim_cpsw->irq_enabled = true; - cpsw_enable_irq(priv); + enable_irq(priv->irqs_table[0]); } } @@ -1335,7 +1322,7 @@ static int cpsw_ndo_open(struct net_device *ndev) if (prim_cpsw->irq_enabled == false) { if ((priv == prim_cpsw) || !netif_running(prim_cpsw->ndev)) { prim_cpsw->irq_enabled = true; - cpsw_enable_irq(prim_cpsw); + enable_irq(prim_cpsw->irqs_table[0]); } } -- cgit v1.2.3-70-g09d2 From 4a0e3e989d66bb7204b163d9cfaa7fa96d0f2023 Mon Sep 17 00:00:00 2001 From: Enrico Mioso Date: Wed, 8 Jul 2015 13:05:57 +0200 Subject: cdc_ncm: Add support for moving NDP to end of NCM frame NCM specs are not actually mandating a specific position in the frame for the NDP (Network Datagram Pointer). However, some Huawei devices will ignore our aggregates if it is not placed after the datagrams it points to. Add support for doing just this, in a per-device configurable way. While at it, update NCM subdrivers, disabling this functionality in all of them, except in huawei_cdc_ncm where it is enabled instead. We aren't making any distinction between different Huawei NCM devices, based on what the vendor driver does. Standard NCM devices are left unaffected: if they are compliant, they should be always usable, still stay on the safe side. This change has been tested and working with a Huawei E3131 device (which works regardless of NDP position), a Huawei E3531 (also working both ways) and an E3372 (which mandates NDP to be after indexed datagrams). V1->V2: - corrected wrong NDP acronym definition - fixed possible NULL pointer dereference - patch cleanup V2->V3: - Properly account for the NDP size when writing new packets to SKB Signed-off-by: Enrico Mioso Signed-off-by: David S. Miller --- drivers/net/usb/cdc_mbim.c | 2 +- drivers/net/usb/cdc_ncm.c | 61 ++++++++++++++++++++++++++++++++++++---- drivers/net/usb/huawei_cdc_ncm.c | 7 +++-- include/linux/usb/cdc_ncm.h | 7 ++++- 4 files changed, 67 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/usb/cdc_mbim.c b/drivers/net/usb/cdc_mbim.c index e4b7a47a825c..efc18e05af0a 100644 --- a/drivers/net/usb/cdc_mbim.c +++ b/drivers/net/usb/cdc_mbim.c @@ -158,7 +158,7 @@ static int cdc_mbim_bind(struct usbnet *dev, struct usb_interface *intf) if (!cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting)) goto err; - ret = cdc_ncm_bind_common(dev, intf, data_altsetting); + ret = cdc_ncm_bind_common(dev, intf, data_altsetting, 0); if (ret) goto err; diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 8067b8fbb0ee..1991e4a24657 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -684,10 +684,12 @@ static void cdc_ncm_free(struct cdc_ncm_ctx *ctx) ctx->tx_curr_skb = NULL; } + kfree(ctx->delayed_ndp16); + kfree(ctx); } -int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting) +int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting, int drvflags) { const struct usb_cdc_union_desc *union_desc = NULL; struct cdc_ncm_ctx *ctx; @@ -855,6 +857,17 @@ advance: /* finish setting up the device specific data */ cdc_ncm_setup(dev); + /* Device-specific flags */ + ctx->drvflags = drvflags; + + /* Allocate the delayed NDP if needed. */ + if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) { + ctx->delayed_ndp16 = kzalloc(ctx->max_ndp_size, GFP_KERNEL); + if (!ctx->delayed_ndp16) + goto error2; + dev_info(&intf->dev, "NDP will be placed at end of frame for this device."); + } + /* override ethtool_ops */ dev->net->ethtool_ops = &cdc_ncm_ethtool_ops; @@ -954,8 +967,11 @@ static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf) if (cdc_ncm_select_altsetting(intf) != CDC_NCM_COMM_ALTSETTING_NCM) return -ENODEV; - /* The NCM data altsetting is fixed */ - ret = cdc_ncm_bind_common(dev, intf, CDC_NCM_DATA_ALTSETTING_NCM); + /* The NCM data altsetting is fixed, so we hard-coded it. + * Additionally, generic NCM devices are assumed to accept arbitrarily + * placed NDP. + */ + ret = cdc_ncm_bind_common(dev, intf, CDC_NCM_DATA_ALTSETTING_NCM, 0); /* * We should get an event when network connection is "connected" or @@ -986,6 +1002,14 @@ static struct usb_cdc_ncm_ndp16 *cdc_ncm_ndp(struct cdc_ncm_ctx *ctx, struct sk_ struct usb_cdc_ncm_nth16 *nth16 = (void *)skb->data; size_t ndpoffset = le16_to_cpu(nth16->wNdpIndex); + /* If NDP should be moved to the end of the NCM package, we can't follow the + * NTH16 header as we would normally do. NDP isn't written to the SKB yet, and + * the wNdpIndex field in the header is actually not consistent with reality. It will be later. + */ + if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) + if (ctx->delayed_ndp16->dwSignature == sign) + return ctx->delayed_ndp16; + /* follow the chain of NDPs, looking for a match */ while (ndpoffset) { ndp16 = (struct usb_cdc_ncm_ndp16 *)(skb->data + ndpoffset); @@ -995,7 +1019,8 @@ static struct usb_cdc_ncm_ndp16 *cdc_ncm_ndp(struct cdc_ncm_ctx *ctx, struct sk_ } /* align new NDP */ - cdc_ncm_align_tail(skb, ctx->tx_ndp_modulus, 0, ctx->tx_max); + if (!(ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END)) + cdc_ncm_align_tail(skb, ctx->tx_ndp_modulus, 0, ctx->tx_max); /* verify that there is room for the NDP and the datagram (reserve) */ if ((ctx->tx_max - skb->len - reserve) < ctx->max_ndp_size) @@ -1008,7 +1033,11 @@ static struct usb_cdc_ncm_ndp16 *cdc_ncm_ndp(struct cdc_ncm_ctx *ctx, struct sk_ nth16->wNdpIndex = cpu_to_le16(skb->len); /* push a new empty NDP */ - ndp16 = (struct usb_cdc_ncm_ndp16 *)memset(skb_put(skb, ctx->max_ndp_size), 0, ctx->max_ndp_size); + if (!(ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END)) + ndp16 = (struct usb_cdc_ncm_ndp16 *)memset(skb_put(skb, ctx->max_ndp_size), 0, ctx->max_ndp_size); + else + ndp16 = ctx->delayed_ndp16; + ndp16->dwSignature = sign; ndp16->wLength = cpu_to_le16(sizeof(struct usb_cdc_ncm_ndp16) + sizeof(struct usb_cdc_ncm_dpe16)); return ndp16; @@ -1023,6 +1052,15 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign) struct sk_buff *skb_out; u16 n = 0, index, ndplen; u8 ready2send = 0; + u32 delayed_ndp_size; + + /* When our NDP gets written in cdc_ncm_ndp(), then skb_out->len gets updated + * accordingly. Otherwise, we should check here. + */ + if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) + delayed_ndp_size = ctx->max_ndp_size; + else + delayed_ndp_size = 0; /* if there is a remaining skb, it gets priority */ if (skb != NULL) { @@ -1077,7 +1115,7 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign) cdc_ncm_align_tail(skb_out, ctx->tx_modulus, ctx->tx_remainder, ctx->tx_max); /* check if we had enough room left for both NDP and frame */ - if (!ndp16 || skb_out->len + skb->len > ctx->tx_max) { + if (!ndp16 || skb_out->len + skb->len + delayed_ndp_size > ctx->tx_max) { if (n == 0) { /* won't fit, MTU problem? */ dev_kfree_skb_any(skb); @@ -1150,6 +1188,17 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign) /* variables will be reset at next call */ } + /* If requested, put NDP at end of frame. */ + if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) { + nth16 = (struct usb_cdc_ncm_nth16 *)skb_out->data; + cdc_ncm_align_tail(skb_out, ctx->tx_ndp_modulus, 0, ctx->tx_max); + nth16->wNdpIndex = cpu_to_le16(skb_out->len); + memcpy(skb_put(skb_out, ctx->max_ndp_size), ctx->delayed_ndp16, ctx->max_ndp_size); + + /* Zero out delayed NDP - signature checking will naturally fail. */ + ndp16 = memset(ctx->delayed_ndp16, 0, ctx->max_ndp_size); + } + /* If collected data size is less or equal ctx->min_tx_pkt * bytes, we send buffers as it is. If we get more data, it * would be more efficient for USB HS mobile device with DMA diff --git a/drivers/net/usb/huawei_cdc_ncm.c b/drivers/net/usb/huawei_cdc_ncm.c index 735f7dadb9a0..2680a65cd5e4 100644 --- a/drivers/net/usb/huawei_cdc_ncm.c +++ b/drivers/net/usb/huawei_cdc_ncm.c @@ -73,11 +73,14 @@ static int huawei_cdc_ncm_bind(struct usbnet *usbnet_dev, struct usb_driver *subdriver = ERR_PTR(-ENODEV); int ret = -ENODEV; struct huawei_cdc_ncm_state *drvstate = (void *)&usbnet_dev->data; + int drvflags = 0; /* altsetting should always be 1 for NCM devices - so we hard-coded - * it here + * it here. Some huawei devices will need the NDP part of the NCM package to + * be at the end of the frame. */ - ret = cdc_ncm_bind_common(usbnet_dev, intf, 1); + drvflags |= CDC_NCM_FLAG_NDP_TO_END; + ret = cdc_ncm_bind_common(usbnet_dev, intf, 1, drvflags); if (ret) goto err; diff --git a/include/linux/usb/cdc_ncm.h b/include/linux/usb/cdc_ncm.h index 7c9b484735c5..1f6526c76ee8 100644 --- a/include/linux/usb/cdc_ncm.h +++ b/include/linux/usb/cdc_ncm.h @@ -80,6 +80,9 @@ #define CDC_NCM_TIMER_INTERVAL_MIN 5UL #define CDC_NCM_TIMER_INTERVAL_MAX (U32_MAX / NSEC_PER_USEC) +/* Driver flags */ +#define CDC_NCM_FLAG_NDP_TO_END 0x02 /* NDP is placed at end of frame */ + #define cdc_ncm_comm_intf_is_mbim(x) ((x)->desc.bInterfaceSubClass == USB_CDC_SUBCLASS_MBIM && \ (x)->desc.bInterfaceProtocol == USB_CDC_PROTO_NONE) #define cdc_ncm_data_intf_is_mbim(x) ((x)->desc.bInterfaceProtocol == USB_CDC_MBIM_PROTO_NTB) @@ -103,9 +106,11 @@ struct cdc_ncm_ctx { spinlock_t mtx; atomic_t stop; + int drvflags; u32 timer_interval; u32 max_ndp_size; + struct usb_cdc_ncm_ndp16 *delayed_ndp16; u32 tx_timer_pending; u32 tx_curr_frame_num; @@ -133,7 +138,7 @@ struct cdc_ncm_ctx { }; u8 cdc_ncm_select_altsetting(struct usb_interface *intf); -int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting); +int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting, int drvflags); void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf); struct sk_buff *cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign); int cdc_ncm_rx_verify_nth16(struct cdc_ncm_ctx *ctx, struct sk_buff *skb_in); -- cgit v1.2.3-70-g09d2 From 2c069a118fe1d80c47dca84e1561045fc7f3cc9e Mon Sep 17 00:00:00 2001 From: Daniel Axtens Date: Fri, 10 Jul 2015 09:04:25 +1000 Subject: cxl: Check if afu is not null in cxl_slbia The pointer to an AFU in the adapter's list of AFUs can be null if we're in the process of removing AFUs. The afu_list_lock doesn't guard against this. Say we have 2 slices, and we're in the process of removing cxl. - We remove the AFUs in order (see cxl_remove). In cxl_remove_afu for AFU 0, we take the lock, set adapter->afu[0] = NULL, and release the lock. - Then we get an slbia. In cxl_slbia we take the lock, and set afu = adapter->afu[0], which is NULL. - Therefore our attempt to check afu->enabled will blow up. Therefore, check if afu is a null pointer before dereferencing it. Cc: stable@vger.kernel.org Signed-off-by: Daniel Axtens Acked-by: Michael Neuling Acked-by: Ian Munsie Signed-off-by: Michael Ellerman --- drivers/misc/cxl/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/misc/cxl/main.c b/drivers/misc/cxl/main.c index 833348e2c9cb..4a164ab8b35a 100644 --- a/drivers/misc/cxl/main.c +++ b/drivers/misc/cxl/main.c @@ -73,7 +73,7 @@ static inline void cxl_slbia_core(struct mm_struct *mm) spin_lock(&adapter->afu_list_lock); for (slice = 0; slice < adapter->slices; slice++) { afu = adapter->afu[slice]; - if (!afu->enabled) + if (!afu || !afu->enabled) continue; rcu_read_lock(); idr_for_each_entry(&afu->contexts_idr, ctx, id) -- cgit v1.2.3-70-g09d2 From fcc028c106e5750aa66dc43595b3f29f88801ff0 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 9 Jul 2015 22:21:20 +0900 Subject: net: axienet: Fix devm_ioremap_resource return value check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Value returned by devm_ioremap_resource() was checked for non-NULL but devm_ioremap_resource() returns IOMEM_ERR_PTR, not NULL. In case of error this could lead to dereference of ERR_PTR. Signed-off-by: Krzysztof Kozlowski Cc: Fixes: 46aa27df8853 ("net: axienet: Use devm_* calls") Reviewed-by: Sören Brinkmann Signed-off-by: David S. Miller --- drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c index 4208dd7ef101..d95f9aae95e7 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c @@ -1530,9 +1530,9 @@ static int axienet_probe(struct platform_device *pdev) /* Map device registers */ ethres = platform_get_resource(pdev, IORESOURCE_MEM, 0); lp->regs = devm_ioremap_resource(&pdev->dev, ethres); - if (!lp->regs) { + if (IS_ERR(lp->regs)) { dev_err(&pdev->dev, "could not map Axi Ethernet regs.\n"); - ret = -ENOMEM; + ret = PTR_ERR(lp->regs); goto free_netdev; } @@ -1599,9 +1599,9 @@ static int axienet_probe(struct platform_device *pdev) goto free_netdev; } lp->dma_regs = devm_ioremap_resource(&pdev->dev, &dmares); - if (!lp->dma_regs) { + if (IS_ERR(lp->dma_regs)) { dev_err(&pdev->dev, "could not map DMA regs\n"); - ret = -ENOMEM; + ret = PTR_ERR(lp->dma_regs); goto free_netdev; } lp->rx_irq = irq_of_parse_and_map(np, 1); -- cgit v1.2.3-70-g09d2 From 6249ecbbb75cd635025cc681fcf51fb8659edbab Mon Sep 17 00:00:00 2001 From: James Hogan Date: Fri, 17 Apr 2015 10:44:15 +0100 Subject: MIPS: Malta: Make GIC FDC IRQ workaround Malta specific Wider testing reveals that the Fast Debug Channel (FDC) interrupt is routed through the GIC just fine on Pistachio SoC, even though it contains interAptiv cores. Clearly the FDC interrupt routing problems previously observed on interAptiv and proAptiv cores are specific to the Malta FPGA bitstreams. Move the workaround for interAptiv and proAptiv out of gic_get_c0_fdc_int() in the GIC irqchip driver into Malta's get_c0_fdc_int() platform callback, to allow the Pistachio SoC to use the FDC interrupt. Signed-off-by: James Hogan Cc: Ralf Baechle Cc: Andrew Bresticker Cc: Thomas Gleixner Cc: Jason Cooper Cc: linux-mips@linux-mips.org Reviewed-by: Andrew Bresticker Cc: James Hartley Patchwork: http://patchwork.linux-mips.org/patch/9748/ Signed-off-by: Ralf Baechle --- arch/mips/mti-malta/malta-time.c | 20 +++++++++++++------- drivers/irqchip/irq-mips-gic.c | 10 ---------- 2 files changed, 13 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/arch/mips/mti-malta/malta-time.c b/arch/mips/mti-malta/malta-time.c index 185e68261f45..5625b190edc0 100644 --- a/arch/mips/mti-malta/malta-time.c +++ b/arch/mips/mti-malta/malta-time.c @@ -119,18 +119,24 @@ void read_persistent_clock(struct timespec *ts) int get_c0_fdc_int(void) { - int mips_cpu_fdc_irq; + /* + * Some cores claim the FDC is routable through the GIC, but it doesn't + * actually seem to be connected for those Malta bitstreams. + */ + switch (current_cpu_type()) { + case CPU_INTERAPTIV: + case CPU_PROAPTIV: + return -1; + }; if (cpu_has_veic) - mips_cpu_fdc_irq = -1; + return -1; else if (gic_present) - mips_cpu_fdc_irq = gic_get_c0_fdc_int(); + return gic_get_c0_fdc_int(); else if (cp0_fdc_irq >= 0) - mips_cpu_fdc_irq = MIPS_CPU_IRQ_BASE + cp0_fdc_irq; + return MIPS_CPU_IRQ_BASE + cp0_fdc_irq; else - mips_cpu_fdc_irq = -1; - - return mips_cpu_fdc_irq; + return -1; } int get_c0_perfcount_int(void) diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index 4400edd1a6c7..b7d54d428b5e 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -257,16 +257,6 @@ int gic_get_c0_fdc_int(void) return MIPS_CPU_IRQ_BASE + cp0_fdc_irq; } - /* - * Some cores claim the FDC is routable but it doesn't actually seem to - * be connected. - */ - switch (current_cpu_type()) { - case CPU_INTERAPTIV: - case CPU_PROAPTIV: - return -1; - } - return irq_create_mapping(gic_irq_domain, GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_FDC)); } -- cgit v1.2.3-70-g09d2 From dbf3c370862d73fcd2c74ca55e254bb02143238d Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 10 Jul 2015 10:11:07 -0700 Subject: Revert "Input: synaptics - allocate 3 slots to keep stability in image sensors" This reverts commit 63c4fda3c0bb841b1aad1298fc7fe94058fc79f8 as it causes issues with detecting 3-finger taps. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=100481 Cc: stable@vger.kernel.org Acked-by: Benjamin Tissoires --- drivers/input/mouse/synaptics.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 35c8d0ceabee..3a32caf06bf1 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -1199,7 +1199,7 @@ static void set_input_params(struct psmouse *psmouse, ABS_MT_POSITION_Y); /* Image sensors can report per-contact pressure */ input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0); - input_mt_init_slots(dev, 3, INPUT_MT_POINTER | INPUT_MT_TRACK); + input_mt_init_slots(dev, 2, INPUT_MT_POINTER | INPUT_MT_TRACK); /* Image sensors can signal 4 and 5 finger clicks */ __set_bit(BTN_TOOL_QUADTAP, dev->keybit); -- cgit v1.2.3-70-g09d2 From c2ad29540cb913bd9e526fae77c35c7fb45f24a3 Mon Sep 17 00:00:00 2001 From: Ross Zwisler Date: Fri, 10 Jul 2015 11:06:13 -0600 Subject: nfit: update block I/O path to use PMEM API Update the nfit block I/O path to use the new PMEM API and to adhere to the read/write flows outlined in the "NVDIMM Block Window Driver Writer's Guide": http://pmem.io/documents/NVDIMM_Driver_Writers_Guide.pdf This includes adding support for targeted NVDIMM flushes called "flush hints" in the ACPI 6.0 specification: http://www.uefi.org/sites/default/files/resources/ACPI_6.0.pdf For performance and media durability the mapping for a BLK aperture is moved to a write-combining mapping which is consistent with memcpy_to_pmem() and wmb_blk(). Signed-off-by: Ross Zwisler Acked-by: Rafael J. Wysocki Signed-off-by: Dan Williams --- drivers/acpi/nfit.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++------ drivers/acpi/nfit.h | 15 ++++++++- 2 files changed, 100 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/nfit.c b/drivers/acpi/nfit.c index a20b7c883ca0..11aa513f2fda 100644 --- a/drivers/acpi/nfit.c +++ b/drivers/acpi/nfit.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include "nfit.h" @@ -305,6 +306,23 @@ static bool add_idt(struct acpi_nfit_desc *acpi_desc, return true; } +static bool add_flush(struct acpi_nfit_desc *acpi_desc, + struct acpi_nfit_flush_address *flush) +{ + struct device *dev = acpi_desc->dev; + struct nfit_flush *nfit_flush = devm_kzalloc(dev, sizeof(*nfit_flush), + GFP_KERNEL); + + if (!nfit_flush) + return false; + INIT_LIST_HEAD(&nfit_flush->list); + nfit_flush->flush = flush; + list_add_tail(&nfit_flush->list, &acpi_desc->flushes); + dev_dbg(dev, "%s: nfit_flush handle: %d hint_count: %d\n", __func__, + flush->device_handle, flush->hint_count); + return true; +} + static void *add_table(struct acpi_nfit_desc *acpi_desc, void *table, const void *end) { @@ -338,7 +356,8 @@ static void *add_table(struct acpi_nfit_desc *acpi_desc, void *table, return err; break; case ACPI_NFIT_TYPE_FLUSH_ADDRESS: - dev_dbg(dev, "%s: flush\n", __func__); + if (!add_flush(acpi_desc, table)) + return err; break; case ACPI_NFIT_TYPE_SMBIOS: dev_dbg(dev, "%s: smbios\n", __func__); @@ -389,6 +408,7 @@ static int nfit_mem_add(struct acpi_nfit_desc *acpi_desc, { u16 dcr = __to_nfit_memdev(nfit_mem)->region_index; struct nfit_memdev *nfit_memdev; + struct nfit_flush *nfit_flush; struct nfit_dcr *nfit_dcr; struct nfit_bdw *nfit_bdw; struct nfit_idt *nfit_idt; @@ -442,6 +462,14 @@ static int nfit_mem_add(struct acpi_nfit_desc *acpi_desc, nfit_mem->idt_bdw = nfit_idt->idt; break; } + + list_for_each_entry(nfit_flush, &acpi_desc->flushes, list) { + if (nfit_flush->flush->device_handle != + nfit_memdev->memdev->device_handle) + continue; + nfit_mem->nfit_flush = nfit_flush; + break; + } break; } @@ -978,6 +1006,24 @@ static u64 to_interleave_offset(u64 offset, struct nfit_blk_mmio *mmio) return mmio->base_offset + line_offset + table_offset + sub_line_offset; } +static void wmb_blk(struct nfit_blk *nfit_blk) +{ + + if (nfit_blk->nvdimm_flush) { + /* + * The first wmb() is needed to 'sfence' all previous writes + * such that they are architecturally visible for the platform + * buffer flush. Note that we've already arranged for pmem + * writes to avoid the cache via arch_memcpy_to_pmem(). The + * final wmb() ensures ordering for the NVDIMM flush write. + */ + wmb(); + writeq(1, nfit_blk->nvdimm_flush); + wmb(); + } else + wmb_pmem(); +} + static u64 read_blk_stat(struct nfit_blk *nfit_blk, unsigned int bw) { struct nfit_blk_mmio *mmio = &nfit_blk->mmio[DCR]; @@ -1012,6 +1058,7 @@ static void write_blk_ctl(struct nfit_blk *nfit_blk, unsigned int bw, offset = to_interleave_offset(offset, mmio); writeq(cmd, mmio->base + offset); + wmb_blk(nfit_blk); /* FIXME: conditionally perform read-back if mandated by firmware */ } @@ -1026,7 +1073,6 @@ static int acpi_nfit_blk_single_io(struct nfit_blk *nfit_blk, base_offset = nfit_blk->bdw_offset + dpa % L1_CACHE_BYTES + lane * mmio->size; - /* TODO: non-temporal access, flush hints, cache management etc... */ write_blk_ctl(nfit_blk, lane, dpa, len, rw); while (len) { unsigned int c; @@ -1045,13 +1091,19 @@ static int acpi_nfit_blk_single_io(struct nfit_blk *nfit_blk, } if (rw) - memcpy(mmio->aperture + offset, iobuf + copied, c); + memcpy_to_pmem(mmio->aperture + offset, + iobuf + copied, c); else - memcpy(iobuf + copied, mmio->aperture + offset, c); + memcpy_from_pmem(iobuf + copied, + mmio->aperture + offset, c); copied += c; len -= c; } + + if (rw) + wmb_blk(nfit_blk); + rc = read_blk_stat(nfit_blk, lane) ? -EIO : 0; return rc; } @@ -1124,7 +1176,7 @@ static void nfit_spa_unmap(struct acpi_nfit_desc *acpi_desc, } static void __iomem *__nfit_spa_map(struct acpi_nfit_desc *acpi_desc, - struct acpi_nfit_system_address *spa) + struct acpi_nfit_system_address *spa, enum spa_map_type type) { resource_size_t start = spa->address; resource_size_t n = spa->length; @@ -1152,8 +1204,15 @@ static void __iomem *__nfit_spa_map(struct acpi_nfit_desc *acpi_desc, if (!res) goto err_mem; - /* TODO: cacheability based on the spa type */ - spa_map->iomem = ioremap_nocache(start, n); + if (type == SPA_MAP_APERTURE) { + /* + * TODO: memremap_pmem() support, but that requires cache + * flushing when the aperture is moved. + */ + spa_map->iomem = ioremap_wc(start, n); + } else + spa_map->iomem = ioremap_nocache(start, n); + if (!spa_map->iomem) goto err_map; @@ -1171,6 +1230,7 @@ static void __iomem *__nfit_spa_map(struct acpi_nfit_desc *acpi_desc, * nfit_spa_map - interleave-aware managed-mappings of acpi_nfit_system_address ranges * @nvdimm_bus: NFIT-bus that provided the spa table entry * @nfit_spa: spa table to map + * @type: aperture or control region * * In the case where block-data-window apertures and * dimm-control-regions are interleaved they will end up sharing a @@ -1180,12 +1240,12 @@ static void __iomem *__nfit_spa_map(struct acpi_nfit_desc *acpi_desc, * unbound. */ static void __iomem *nfit_spa_map(struct acpi_nfit_desc *acpi_desc, - struct acpi_nfit_system_address *spa) + struct acpi_nfit_system_address *spa, enum spa_map_type type) { void __iomem *iomem; mutex_lock(&acpi_desc->spa_map_mutex); - iomem = __nfit_spa_map(acpi_desc, spa); + iomem = __nfit_spa_map(acpi_desc, spa, type); mutex_unlock(&acpi_desc->spa_map_mutex); return iomem; @@ -1212,6 +1272,7 @@ static int acpi_nfit_blk_region_enable(struct nvdimm_bus *nvdimm_bus, struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus); struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc); struct nd_blk_region *ndbr = to_nd_blk_region(dev); + struct nfit_flush *nfit_flush; struct nfit_blk_mmio *mmio; struct nfit_blk *nfit_blk; struct nfit_mem *nfit_mem; @@ -1237,7 +1298,8 @@ static int acpi_nfit_blk_region_enable(struct nvdimm_bus *nvdimm_bus, /* map block aperture memory */ nfit_blk->bdw_offset = nfit_mem->bdw->offset; mmio = &nfit_blk->mmio[BDW]; - mmio->base = nfit_spa_map(acpi_desc, nfit_mem->spa_bdw); + mmio->base = nfit_spa_map(acpi_desc, nfit_mem->spa_bdw, + SPA_MAP_APERTURE); if (!mmio->base) { dev_dbg(dev, "%s: %s failed to map bdw\n", __func__, nvdimm_name(nvdimm)); @@ -1259,7 +1321,8 @@ static int acpi_nfit_blk_region_enable(struct nvdimm_bus *nvdimm_bus, nfit_blk->cmd_offset = nfit_mem->dcr->command_offset; nfit_blk->stat_offset = nfit_mem->dcr->status_offset; mmio = &nfit_blk->mmio[DCR]; - mmio->base = nfit_spa_map(acpi_desc, nfit_mem->spa_dcr); + mmio->base = nfit_spa_map(acpi_desc, nfit_mem->spa_dcr, + SPA_MAP_CONTROL); if (!mmio->base) { dev_dbg(dev, "%s: %s failed to map dcr\n", __func__, nvdimm_name(nvdimm)); @@ -1277,6 +1340,17 @@ static int acpi_nfit_blk_region_enable(struct nvdimm_bus *nvdimm_bus, return rc; } + nfit_flush = nfit_mem->nfit_flush; + if (nfit_flush && nfit_flush->flush->hint_count != 0) { + nfit_blk->nvdimm_flush = devm_ioremap_nocache(dev, + nfit_flush->flush->hint_address[0], 8); + if (!nfit_blk->nvdimm_flush) + return -ENOMEM; + } + + if (!arch_has_pmem_api() && !nfit_blk->nvdimm_flush) + dev_warn(dev, "unable to guarantee persistence of writes\n"); + if (mmio->line_size == 0) return 0; @@ -1459,6 +1533,7 @@ int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, acpi_size sz) INIT_LIST_HEAD(&acpi_desc->dcrs); INIT_LIST_HEAD(&acpi_desc->bdws); INIT_LIST_HEAD(&acpi_desc->idts); + INIT_LIST_HEAD(&acpi_desc->flushes); INIT_LIST_HEAD(&acpi_desc->memdevs); INIT_LIST_HEAD(&acpi_desc->dimms); mutex_init(&acpi_desc->spa_map_mutex); diff --git a/drivers/acpi/nfit.h b/drivers/acpi/nfit.h index 81f2e8c5a79c..815cb561cdba 100644 --- a/drivers/acpi/nfit.h +++ b/drivers/acpi/nfit.h @@ -60,6 +60,11 @@ struct nfit_idt { struct list_head list; }; +struct nfit_flush { + struct acpi_nfit_flush_address *flush; + struct list_head list; +}; + struct nfit_memdev { struct acpi_nfit_memory_map *memdev; struct list_head list; @@ -77,6 +82,7 @@ struct nfit_mem { struct acpi_nfit_system_address *spa_bdw; struct acpi_nfit_interleave *idt_dcr; struct acpi_nfit_interleave *idt_bdw; + struct nfit_flush *nfit_flush; struct list_head list; struct acpi_device *adev; unsigned long dsm_mask; @@ -88,6 +94,7 @@ struct acpi_nfit_desc { struct mutex spa_map_mutex; struct list_head spa_maps; struct list_head memdevs; + struct list_head flushes; struct list_head dimms; struct list_head spas; struct list_head dcrs; @@ -109,7 +116,7 @@ struct nfit_blk { struct nfit_blk_mmio { union { void __iomem *base; - void *aperture; + void __pmem *aperture; }; u64 size; u64 base_offset; @@ -123,6 +130,12 @@ struct nfit_blk { u64 bdw_offset; /* post interleave offset */ u64 stat_offset; u64 cmd_offset; + void __iomem *nvdimm_flush; +}; + +enum spa_map_type { + SPA_MAP_CONTROL, + SPA_MAP_APERTURE, }; struct nfit_spa_mapping { -- cgit v1.2.3-70-g09d2 From f0f2c072cf530d5b8890be5051cc8b36b0c54cce Mon Sep 17 00:00:00 2001 From: Ross Zwisler Date: Fri, 10 Jul 2015 11:06:14 -0600 Subject: nfit: add support for NVDIMM "latch" flag Add support in the NFIT BLK I/O path for the "latch" flag defined in the "Get Block NVDIMM Flags" _DSM function: http://pmem.io/documents/NVDIMM_DSM_Interface_Example.pdf This flag requires the driver to read back the command register after it is written in the block I/O path. This ensures that the hardware has fully processed the new command and moved the aperture appropriately. Signed-off-by: Ross Zwisler Acked-by: Rafael J. Wysocki Signed-off-by: Dan Williams --- drivers/acpi/nfit.c | 33 ++++++++++++++++++++++++++++++++- drivers/acpi/nfit.h | 5 +++++ 2 files changed, 37 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/nfit.c b/drivers/acpi/nfit.c index 11aa513f2fda..628a42c41ab1 100644 --- a/drivers/acpi/nfit.c +++ b/drivers/acpi/nfit.c @@ -1059,7 +1059,9 @@ static void write_blk_ctl(struct nfit_blk *nfit_blk, unsigned int bw, writeq(cmd, mmio->base + offset); wmb_blk(nfit_blk); - /* FIXME: conditionally perform read-back if mandated by firmware */ + + if (nfit_blk->dimm_flags & ND_BLK_DCR_LATCH) + readq(mmio->base + offset); } static int acpi_nfit_blk_single_io(struct nfit_blk *nfit_blk, @@ -1266,6 +1268,28 @@ static int nfit_blk_init_interleave(struct nfit_blk_mmio *mmio, return 0; } +static int acpi_nfit_blk_get_flags(struct nvdimm_bus_descriptor *nd_desc, + struct nvdimm *nvdimm, struct nfit_blk *nfit_blk) +{ + struct nd_cmd_dimm_flags flags; + int rc; + + memset(&flags, 0, sizeof(flags)); + rc = nd_desc->ndctl(nd_desc, nvdimm, ND_CMD_DIMM_FLAGS, &flags, + sizeof(flags)); + + if (rc >= 0 && flags.status == 0) + nfit_blk->dimm_flags = flags.flags; + else if (rc == -ENOTTY) { + /* fall back to a conservative default */ + nfit_blk->dimm_flags = ND_BLK_DCR_LATCH; + rc = 0; + } else + rc = -ENXIO; + + return rc; +} + static int acpi_nfit_blk_region_enable(struct nvdimm_bus *nvdimm_bus, struct device *dev) { @@ -1340,6 +1364,13 @@ static int acpi_nfit_blk_region_enable(struct nvdimm_bus *nvdimm_bus, return rc; } + rc = acpi_nfit_blk_get_flags(nd_desc, nvdimm, nfit_blk); + if (rc < 0) { + dev_dbg(dev, "%s: %s failed get DIMM flags\n", + __func__, nvdimm_name(nvdimm)); + return rc; + } + nfit_flush = nfit_mem->nfit_flush; if (nfit_flush && nfit_flush->flush->hint_count != 0) { nfit_blk->nvdimm_flush = devm_ioremap_nocache(dev, diff --git a/drivers/acpi/nfit.h b/drivers/acpi/nfit.h index 815cb561cdba..79b6d83875c1 100644 --- a/drivers/acpi/nfit.h +++ b/drivers/acpi/nfit.h @@ -40,6 +40,10 @@ enum nfit_uuids { NFIT_UUID_MAX, }; +enum { + ND_BLK_DCR_LATCH = 2, +}; + struct nfit_spa { struct acpi_nfit_system_address *spa; struct list_head list; @@ -131,6 +135,7 @@ struct nfit_blk { u64 stat_offset; u64 cmd_offset; void __iomem *nvdimm_flush; + u32 dimm_flags; }; enum spa_map_type { -- cgit v1.2.3-70-g09d2 From cb908ed3495496b9973a2b9ed1a60f43933fdf01 Mon Sep 17 00:00:00 2001 From: Alex Ivanov Date: Mon, 15 Jun 2015 08:50:45 +0300 Subject: stifb: Implement hardware accelerated copyarea This patch adds hardware assisted scrolling. The code is based upon the following investigation: https://parisc.wiki.kernel.org/index.php/NGLE#Blitter A simple 'time ls -la /usr/bin' test shows 1.6x speed increase over soft copy and 2.3x increase over FBINFO_READS_FAST (prefer soft copy over screen redraw) on Artist framebuffer. Signed-off-by: Alex Ivanov Signed-off-by: Helge Deller --- drivers/video/fbdev/stifb.c | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/video/fbdev/stifb.c b/drivers/video/fbdev/stifb.c index 86621fabbb8b..735355b0e023 100644 --- a/drivers/video/fbdev/stifb.c +++ b/drivers/video/fbdev/stifb.c @@ -121,6 +121,7 @@ static int __initdata stifb_bpp_pref[MAX_STI_ROMS]; #define REG_3 0x0004a0 #define REG_4 0x000600 #define REG_6 0x000800 +#define REG_7 0x000804 #define REG_8 0x000820 #define REG_9 0x000a04 #define REG_10 0x018000 @@ -135,6 +136,8 @@ static int __initdata stifb_bpp_pref[MAX_STI_ROMS]; #define REG_21 0x200218 #define REG_22 0x0005a0 #define REG_23 0x0005c0 +#define REG_24 0x000808 +#define REG_25 0x000b00 #define REG_26 0x200118 #define REG_27 0x200308 #define REG_32 0x21003c @@ -429,6 +432,9 @@ ARTIST_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable) #define SET_LENXY_START_RECFILL(fb, lenxy) \ WRITE_WORD(lenxy, fb, REG_9) +#define SETUP_COPYAREA(fb) \ + WRITE_BYTE(0, fb, REG_16b1) + static void HYPER_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable) { @@ -1004,6 +1010,36 @@ stifb_blank(int blank_mode, struct fb_info *info) return 0; } +static void +stifb_copyarea(struct fb_info *info, const struct fb_copyarea *area) +{ + struct stifb_info *fb = container_of(info, struct stifb_info, info); + + SETUP_COPYAREA(fb); + + SETUP_HW(fb); + if (fb->info.var.bits_per_pixel == 32) { + WRITE_WORD(0xBBA0A000, fb, REG_10); + + NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffffff); + } else { + WRITE_WORD(fb->id == S9000_ID_HCRX ? 0x13a02000 : 0x13a01000, fb, REG_10); + + NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xff); + } + + NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb, + IBOvals(RopSrc, MaskAddrOffset(0), + BitmapExtent08, StaticReg(1), + DataDynamic, MaskOtc, BGx(0), FGx(0))); + + WRITE_WORD(((area->sx << 16) | area->sy), fb, REG_24); + WRITE_WORD(((area->width << 16) | area->height), fb, REG_7); + WRITE_WORD(((area->dx << 16) | area->dy), fb, REG_25); + + SETUP_FB(fb); +} + static void __init stifb_init_display(struct stifb_info *fb) { @@ -1069,7 +1105,7 @@ static struct fb_ops stifb_ops = { .fb_setcolreg = stifb_setcolreg, .fb_blank = stifb_blank, .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, + .fb_copyarea = stifb_copyarea, .fb_imageblit = cfb_imageblit, }; @@ -1258,7 +1294,7 @@ static int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref) info->fbops = &stifb_ops; info->screen_base = ioremap_nocache(REGION_BASE(fb,1), fix->smem_len); info->screen_size = fix->smem_len; - info->flags = FBINFO_DEFAULT; + info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA; info->pseudo_palette = &fb->pseudo_palette; /* This has to be done !!! */ -- cgit v1.2.3-70-g09d2 From 145c37084e3e6584b95f82361922965cc3af41bf Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Fri, 10 Jul 2015 21:20:28 +0900 Subject: Doc: z8530book: Fix typo in API-z8530-sync-txdma-open.html This patch fix a spelling typo found in API-z8530-sync-txdma-open.html. It is because this file was generated from comment in source, I have to fix comment in source. Signed-off-by: Masanari Iida Signed-off-by: David S. Miller --- drivers/net/wan/z85230.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wan/z85230.c b/drivers/net/wan/z85230.c index feacc3b994b7..2f0bd6955f33 100644 --- a/drivers/net/wan/z85230.c +++ b/drivers/net/wan/z85230.c @@ -1044,7 +1044,7 @@ EXPORT_SYMBOL(z8530_sync_dma_close); * @dev: The network device to attach * @c: The Z8530 channel to configure in sync DMA mode. * - * Set up a Z85x30 device for synchronous DMA tranmission. One + * Set up a Z85x30 device for synchronous DMA transmission. One * ISA DMA channel must be available for this to work. The receive * side is run in PIO mode, but then it has the bigger FIFO. */ -- cgit v1.2.3-70-g09d2 From 22401ff17f993bda9acd14ac39213e6f9bb985d0 Mon Sep 17 00:00:00 2001 From: Enrico Mioso Date: Sat, 11 Jul 2015 17:30:01 +0200 Subject: cdc_ncm: update specs URL Update referenced specs link to reflect actual file version and location. Signed-off-by: Enrico Mioso Signed-off-by: David S. Miller --- drivers/net/usb/cdc_ncm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 1991e4a24657..db40175b1a0b 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -6,7 +6,7 @@ * Original author: Hans Petter Selasky * * USB Host Driver for Network Control Model (NCM) - * http://www.usb.org/developers/devclass_docs/NCM10.zip + * http://www.usb.org/developers/docs/devclass_docs/NCM10_012011.zip * * The NCM encoding, decoding and initialization logic * derives from FreeBSD 8.x. if_cdce.c and if_cdcereg.h -- cgit v1.2.3-70-g09d2 From c590032f9ab8d03aab235a7601db22a267c2d958 Mon Sep 17 00:00:00 2001 From: Petri Gynther Date: Fri, 10 Jul 2015 16:20:00 -0700 Subject: net: bcmgenet: fix accounting of packet drops vs errors bcmgenet driver needs to separate packet drops from packet errors. When the driver has to drop a *good* packet, due to lack of buffers or replacement skbs, increment only dev->stats.[rx|tx]_dropped. When the driver encounters a bad Rx packet or Tx error, increment only dev->stats.[rx|tx]_errors + relevant detailed error counter. Signed-off-by: Petri Gynther Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index b43b2cb9b830..64c1e9db6b0b 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -1230,7 +1230,6 @@ static struct sk_buff *bcmgenet_put_tx_csum(struct net_device *dev, new_skb = skb_realloc_headroom(skb, sizeof(*status)); dev_kfree_skb(skb); if (!new_skb) { - dev->stats.tx_errors++; dev->stats.tx_dropped++; return NULL; } @@ -1465,7 +1464,6 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, if (unlikely(!skb)) { dev->stats.rx_dropped++; - dev->stats.rx_errors++; goto next; } @@ -1493,7 +1491,6 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, if (unlikely(!(dma_flag & DMA_EOP) || !(dma_flag & DMA_SOP))) { netif_err(priv, rx_status, dev, "dropping fragmented packet!\n"); - dev->stats.rx_dropped++; dev->stats.rx_errors++; dev_kfree_skb_any(skb); goto next; @@ -1515,7 +1512,6 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, dev->stats.rx_frame_errors++; if (dma_flag & DMA_RX_LG) dev->stats.rx_length_errors++; - dev->stats.rx_dropped++; dev->stats.rx_errors++; dev_kfree_skb_any(skb); goto next; -- cgit v1.2.3-70-g09d2 From 5e63e6baa159fa8c787cf783dbf3d77fbea97331 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Sat, 20 Jun 2015 03:32:46 +0300 Subject: can: rcar_can: fix IRQ check rcar_can_probe() regards 0 as a wrong IRQ #, despite platform_get_irq() that it calls returns negative error code in that case. This leads to the following being printed to the console when attempting to open the device: error requesting interrupt fffffffa because rcar_can_open() calls request_irq() with a negative IRQ #, and that function naturally fails with -EINVAL. Check for the negative error codes instead and propagate them upstream instead of just returning -ENODEV. Fixes: fd1159318e55 ("can: add Renesas R-Car CAN driver") Signed-off-by: Sergei Shtylyov Cc: linux-stable Signed-off-by: Marc Kleine-Budde --- drivers/net/can/rcar_can.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/can/rcar_can.c b/drivers/net/can/rcar_can.c index 7deb80dcbe8c..93017c09cfc3 100644 --- a/drivers/net/can/rcar_can.c +++ b/drivers/net/can/rcar_can.c @@ -758,8 +758,9 @@ static int rcar_can_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); - if (!irq) { + if (irq < 0) { dev_err(&pdev->dev, "No IRQ resource\n"); + err = irq; goto fail; } -- cgit v1.2.3-70-g09d2 From c1a4c87b06fa564d6e2760a12d4e5a09badc684b Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Sat, 20 Jun 2015 03:33:53 +0300 Subject: can: rcar_can: print signed IRQ # Printing IRQ # using "%x" and "%u" unsigned formats isn't quite correct as 'ndev->irq' is of type *int*, so the "%d" format needs to be used instead. While fixing this, beautify the dev_info() message in rcar_can_probe() a bit. Fixes: fd1159318e55 ("can: add Renesas R-Car CAN driver") Signed-off-by: Sergei Shtylyov Signed-off-by: Marc Kleine-Budde --- drivers/net/can/rcar_can.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/can/rcar_can.c b/drivers/net/can/rcar_can.c index 93017c09cfc3..2f9ebad4ff56 100644 --- a/drivers/net/can/rcar_can.c +++ b/drivers/net/can/rcar_can.c @@ -526,7 +526,7 @@ static int rcar_can_open(struct net_device *ndev) napi_enable(&priv->napi); err = request_irq(ndev->irq, rcar_can_interrupt, 0, ndev->name, ndev); if (err) { - netdev_err(ndev, "error requesting interrupt %x\n", ndev->irq); + netdev_err(ndev, "error requesting interrupt %d\n", ndev->irq); goto out_close; } can_led_event(ndev, CAN_LED_EVENT_OPEN); @@ -824,7 +824,7 @@ static int rcar_can_probe(struct platform_device *pdev) devm_can_led_init(ndev); - dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%u)\n", + dev_info(&pdev->dev, "device registered (regs @ %p, IRQ%d)\n", priv->regs, ndev->irq); return 0; -- cgit v1.2.3-70-g09d2 From 3255f68c132a8ed784b9fe1804ef4642a1d16b9a Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Sat, 20 Jun 2015 03:34:55 +0300 Subject: can: rcar_can: fix typo in error message Fix typo in the first error message printed by rcar_can_open(). Based on the original patch by Vladimir Barinov. Fixes: 862e2b6af941 ("can: rcar_can: support all input clocks") Reported-by: Vladimir Barinov Signed-off-by: Sergei Shtylyov Signed-off-by: Marc Kleine-Budde --- drivers/net/can/rcar_can.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/can/rcar_can.c b/drivers/net/can/rcar_can.c index 2f9ebad4ff56..310a0cd20679 100644 --- a/drivers/net/can/rcar_can.c +++ b/drivers/net/can/rcar_can.c @@ -508,7 +508,8 @@ static int rcar_can_open(struct net_device *ndev) err = clk_prepare_enable(priv->clk); if (err) { - netdev_err(ndev, "failed to enable periperal clock, error %d\n", + netdev_err(ndev, + "failed to enable peripheral clock, error %d\n", err); goto out; } -- cgit v1.2.3-70-g09d2 From ae185f19662565f5320e49247faab8752a977642 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Sat, 20 Jun 2015 03:50:35 +0300 Subject: can: rcar_can: print request_irq() error code Also print the error code when the request_irq() call fails in rcar_can_open(), rewording the error message... Signed-off-by: Sergei Shtylyov Signed-off-by: Marc Kleine-Budde --- drivers/net/can/rcar_can.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/can/rcar_can.c b/drivers/net/can/rcar_can.c index 310a0cd20679..5e81afffc073 100644 --- a/drivers/net/can/rcar_can.c +++ b/drivers/net/can/rcar_can.c @@ -527,7 +527,8 @@ static int rcar_can_open(struct net_device *ndev) napi_enable(&priv->napi); err = request_irq(ndev->irq, rcar_can_interrupt, 0, ndev->name, ndev); if (err) { - netdev_err(ndev, "error requesting interrupt %d\n", ndev->irq); + netdev_err(ndev, "request_irq(%d) failed, error %d\n", + ndev->irq, err); goto out_close; } can_led_event(ndev, CAN_LED_EVENT_OPEN); -- cgit v1.2.3-70-g09d2 From 585bc2ac4cc0e2398f5b128018247f51fa3e0e12 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Sat, 20 Jun 2015 03:51:34 +0300 Subject: can: rcar_can: unify error messages All the error messages in the driver but the ones from devm_clk_get() failures use similar format. Make those two messages consitent with others. Signed-off-by: Sergei Shtylyov Signed-off-by: Marc Kleine-Budde --- drivers/net/can/rcar_can.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/can/rcar_can.c b/drivers/net/can/rcar_can.c index 5e81afffc073..7bd54191f962 100644 --- a/drivers/net/can/rcar_can.c +++ b/drivers/net/can/rcar_can.c @@ -785,7 +785,8 @@ static int rcar_can_probe(struct platform_device *pdev) priv->clk = devm_clk_get(&pdev->dev, "clkp1"); if (IS_ERR(priv->clk)) { err = PTR_ERR(priv->clk); - dev_err(&pdev->dev, "cannot get peripheral clock: %d\n", err); + dev_err(&pdev->dev, "cannot get peripheral clock, error %d\n", + err); goto fail_clk; } @@ -797,7 +798,7 @@ static int rcar_can_probe(struct platform_device *pdev) priv->can_clk = devm_clk_get(&pdev->dev, clock_names[clock_select]); if (IS_ERR(priv->can_clk)) { err = PTR_ERR(priv->can_clk); - dev_err(&pdev->dev, "cannot get CAN clock: %d\n", err); + dev_err(&pdev->dev, "cannot get CAN clock, error %d\n", err); goto fail_clk; } -- cgit v1.2.3-70-g09d2 From 033365191136c97f88c81b7bd0011414db28bb4e Mon Sep 17 00:00:00 2001 From: "J.D. Schroeder" Date: Wed, 8 Jul 2015 14:38:12 +0300 Subject: can: c_can: Fix default pinmux glitch at init The previous change 3973c526ae9c (net: can: c_can: Disable pins when CAN interface is down) causes a slight glitch on the pinctrl settings when used. Since commit ab78029 (drivers/pinctrl: grab default handles from device core), the device core will automatically set the default pins. This causes the pins to be momentarily set to the default and then to the sleep state in register_c_can_dev(). By adding an optional "enable" state, boards can set the default pin state to be disabled and avoid the glitch when the switch from default to sleep first occurs. If the "enable" state is not available c_can_pinctrl_select_state() falls back to using the "default" pinctrl state. [Roger Q] - Forward port to v4.2 and use pinctrl_get_select(). Signed-off-by: J.D. Schroeder Signed-off-by: Roger Quadros Reviewed-by: Grygorii Strashko Cc: linux-stable Signed-off-by: Marc Kleine-Budde --- drivers/net/can/c_can/c_can.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c index 041525d2595c..5d214d135332 100644 --- a/drivers/net/can/c_can/c_can.c +++ b/drivers/net/can/c_can/c_can.c @@ -592,6 +592,7 @@ static int c_can_start(struct net_device *dev) { struct c_can_priv *priv = netdev_priv(dev); int err; + struct pinctrl *p; /* basic c_can configuration */ err = c_can_chip_config(dev); @@ -604,8 +605,13 @@ static int c_can_start(struct net_device *dev) priv->can.state = CAN_STATE_ERROR_ACTIVE; - /* activate pins */ - pinctrl_pm_select_default_state(dev->dev.parent); + /* Attempt to use "active" if available else use "default" */ + p = pinctrl_get_select(priv->device, "active"); + if (!IS_ERR(p)) + pinctrl_put(p); + else + pinctrl_pm_select_default_state(priv->device); + return 0; } -- cgit v1.2.3-70-g09d2 From d3b58c47d330de8c29898fe9746f7530408f8a59 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Fri, 26 Jun 2015 11:58:19 +0200 Subject: can: replace timestamp as unique skb attribute Commit 514ac99c64b "can: fix multiple delivery of a single CAN frame for overlapping CAN filters" requires the skb->tstamp to be set to check for identical CAN skbs. Without timestamping to be required by user space applications this timestamp was not generated which lead to commit 36c01245eb8 "can: fix loss of CAN frames in raw_rcv" - which forces the timestamp to be set in all CAN related skbuffs by introducing several __net_timestamp() calls. This forces e.g. out of tree drivers which are not using alloc_can{,fd}_skb() to add __net_timestamp() after skbuff creation to prevent the frame loss fixed in mainline Linux. This patch removes the timestamp dependency and uses an atomic counter to create an unique identifier together with the skbuff pointer. Btw: the new skbcnt element introduced in struct can_skb_priv has to be initialized with zero in out-of-tree drivers which are not using alloc_can{,fd}_skb() too. Signed-off-by: Oliver Hartkopp Cc: linux-stable Signed-off-by: Marc Kleine-Budde --- drivers/net/can/dev.c | 7 ++----- drivers/net/can/slcan.c | 2 +- drivers/net/can/vcan.c | 3 --- include/linux/can/skb.h | 2 ++ net/can/af_can.c | 12 +++++++----- net/can/bcm.c | 2 ++ net/can/raw.c | 7 ++++--- 7 files changed, 18 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index e9b1810d319f..aede704605c6 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -440,9 +440,6 @@ unsigned int can_get_echo_skb(struct net_device *dev, unsigned int idx) struct can_frame *cf = (struct can_frame *)skb->data; u8 dlc = cf->can_dlc; - if (!(skb->tstamp.tv64)) - __net_timestamp(skb); - netif_rx(priv->echo_skb[idx]); priv->echo_skb[idx] = NULL; @@ -578,7 +575,6 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf) if (unlikely(!skb)) return NULL; - __net_timestamp(skb); skb->protocol = htons(ETH_P_CAN); skb->pkt_type = PACKET_BROADCAST; skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -589,6 +585,7 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf) can_skb_reserve(skb); can_skb_prv(skb)->ifindex = dev->ifindex; + can_skb_prv(skb)->skbcnt = 0; *cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame)); memset(*cf, 0, sizeof(struct can_frame)); @@ -607,7 +604,6 @@ struct sk_buff *alloc_canfd_skb(struct net_device *dev, if (unlikely(!skb)) return NULL; - __net_timestamp(skb); skb->protocol = htons(ETH_P_CANFD); skb->pkt_type = PACKET_BROADCAST; skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -618,6 +614,7 @@ struct sk_buff *alloc_canfd_skb(struct net_device *dev, can_skb_reserve(skb); can_skb_prv(skb)->ifindex = dev->ifindex; + can_skb_prv(skb)->skbcnt = 0; *cfd = (struct canfd_frame *)skb_put(skb, sizeof(struct canfd_frame)); memset(*cfd, 0, sizeof(struct canfd_frame)); diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c index f64f5290d6f8..a23a7af8eb9a 100644 --- a/drivers/net/can/slcan.c +++ b/drivers/net/can/slcan.c @@ -207,7 +207,6 @@ static void slc_bump(struct slcan *sl) if (!skb) return; - __net_timestamp(skb); skb->dev = sl->dev; skb->protocol = htons(ETH_P_CAN); skb->pkt_type = PACKET_BROADCAST; @@ -215,6 +214,7 @@ static void slc_bump(struct slcan *sl) can_skb_reserve(skb); can_skb_prv(skb)->ifindex = sl->dev->ifindex; + can_skb_prv(skb)->skbcnt = 0; memcpy(skb_put(skb, sizeof(struct can_frame)), &cf, sizeof(struct can_frame)); diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c index 0ce868de855d..674f367087c5 100644 --- a/drivers/net/can/vcan.c +++ b/drivers/net/can/vcan.c @@ -78,9 +78,6 @@ static void vcan_rx(struct sk_buff *skb, struct net_device *dev) skb->dev = dev; skb->ip_summed = CHECKSUM_UNNECESSARY; - if (!(skb->tstamp.tv64)) - __net_timestamp(skb); - netif_rx_ni(skb); } diff --git a/include/linux/can/skb.h b/include/linux/can/skb.h index b6a52a4b457a..51bb6532785c 100644 --- a/include/linux/can/skb.h +++ b/include/linux/can/skb.h @@ -27,10 +27,12 @@ /** * struct can_skb_priv - private additional data inside CAN sk_buffs * @ifindex: ifindex of the first interface the CAN frame appeared on + * @skbcnt: atomic counter to have an unique id together with skb pointer * @cf: align to the following CAN frame at skb->data */ struct can_skb_priv { int ifindex; + int skbcnt; struct can_frame cf[0]; }; diff --git a/net/can/af_can.c b/net/can/af_can.c index 7933e62a7318..166d436196c1 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c @@ -89,6 +89,8 @@ struct timer_list can_stattimer; /* timer for statistics update */ struct s_stats can_stats; /* packet statistics */ struct s_pstats can_pstats; /* receive list statistics */ +static atomic_t skbcounter = ATOMIC_INIT(0); + /* * af_can socket functions */ @@ -310,12 +312,8 @@ int can_send(struct sk_buff *skb, int loop) return err; } - if (newskb) { - if (!(newskb->tstamp.tv64)) - __net_timestamp(newskb); - + if (newskb) netif_rx_ni(newskb); - } /* update statistics */ can_stats.tx_frames++; @@ -683,6 +681,10 @@ static void can_receive(struct sk_buff *skb, struct net_device *dev) can_stats.rx_frames++; can_stats.rx_frames_delta++; + /* create non-zero unique skb identifier together with *skb */ + while (!(can_skb_prv(skb)->skbcnt)) + can_skb_prv(skb)->skbcnt = atomic_inc_return(&skbcounter); + rcu_read_lock(); /* deliver the packet to sockets listening on all devices */ diff --git a/net/can/bcm.c b/net/can/bcm.c index b523453585be..a1ba6875c2a2 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c @@ -261,6 +261,7 @@ static void bcm_can_tx(struct bcm_op *op) can_skb_reserve(skb); can_skb_prv(skb)->ifindex = dev->ifindex; + can_skb_prv(skb)->skbcnt = 0; memcpy(skb_put(skb, CFSIZ), cf, CFSIZ); @@ -1217,6 +1218,7 @@ static int bcm_tx_send(struct msghdr *msg, int ifindex, struct sock *sk) } can_skb_prv(skb)->ifindex = dev->ifindex; + can_skb_prv(skb)->skbcnt = 0; skb->dev = dev; can_skb_set_owner(skb, sk); err = can_send(skb, 1); /* send with loopback */ diff --git a/net/can/raw.c b/net/can/raw.c index 31b9748cbb4e..2e67b1423cd3 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -75,7 +75,7 @@ MODULE_ALIAS("can-proto-1"); */ struct uniqframe { - ktime_t tstamp; + int skbcnt; const struct sk_buff *skb; unsigned int join_rx_count; }; @@ -133,7 +133,7 @@ static void raw_rcv(struct sk_buff *oskb, void *data) /* eliminate multiple filter matches for the same skb */ if (this_cpu_ptr(ro->uniq)->skb == oskb && - ktime_equal(this_cpu_ptr(ro->uniq)->tstamp, oskb->tstamp)) { + this_cpu_ptr(ro->uniq)->skbcnt == can_skb_prv(oskb)->skbcnt) { if (ro->join_filters) { this_cpu_inc(ro->uniq->join_rx_count); /* drop frame until all enabled filters matched */ @@ -144,7 +144,7 @@ static void raw_rcv(struct sk_buff *oskb, void *data) } } else { this_cpu_ptr(ro->uniq)->skb = oskb; - this_cpu_ptr(ro->uniq)->tstamp = oskb->tstamp; + this_cpu_ptr(ro->uniq)->skbcnt = can_skb_prv(oskb)->skbcnt; this_cpu_ptr(ro->uniq)->join_rx_count = 1; /* drop first frame to check all enabled filters? */ if (ro->join_filters && ro->count > 1) @@ -749,6 +749,7 @@ static int raw_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) can_skb_reserve(skb); can_skb_prv(skb)->ifindex = dev->ifindex; + can_skb_prv(skb)->skbcnt = 0; err = memcpy_from_msg(skb_put(skb, size), msg, size); if (err < 0) -- cgit v1.2.3-70-g09d2 From 01e2d0627a9a6edb24c37db45db5ecb31e9de808 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 12 Jul 2015 15:00:20 -0700 Subject: Revert "drm/i915: Use crtc_state->active in primary check_plane func" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit dec4f799d0a4c9edae20512fa60b0a36f3299ca2. Jörg Otte reports a NULL pointder dereference due to this commit, as 'crtc_state' very much can be NULL: crtc_state = state->base.state ? intel_atomic_get_crtc_state(state->base.state, intel_crtc) : NULL; So the change to test 'crtc_state->base.active' cannot possibly be correct as-is. There may be some other minimal fix (like just checking crtc_state for NULL), but I'm just reverting it now for the rc2 release, and people like Daniel Vetter who actually know this code will figure out what the right solution is in the longer term. Reported-and-bisected-by: Jörg Otte Cc: Ander Conselvan de Oliveira Cc: Jani Nikula Cc: Daniel Vetter CC: Maarten Lankhorst Signed-off-by: Linus Torvalds --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ba9321998a41..647b1404c441 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13276,7 +13276,7 @@ intel_check_primary_plane(struct drm_plane *plane, if (ret) return ret; - if (crtc_state->base.active) { + if (intel_crtc->active) { struct intel_plane_state *old_state = to_intel_plane_state(plane->state); -- cgit v1.2.3-70-g09d2