diff options
Diffstat (limited to 'drivers')
111 files changed, 3474 insertions, 1856 deletions
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index 4a3ac31c07d0..3b0118786b43 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -20,6 +20,7 @@ #include <linux/sizes.h> #include <linux/limits.h> #include <linux/clk/clk-conf.h> +#include <linux/platform_device.h> #include <asm/irq.h> @@ -193,14 +194,16 @@ static const struct dev_pm_ops amba_pm = { /* * Primecells are part of the Advanced Microcontroller Bus Architecture, * so we call the bus "amba". + * DMA configuration for platform and AMBA bus is same. So here we reuse + * platform's DMA config routine. */ struct bus_type amba_bustype = { .name = "amba", .dev_groups = amba_dev_groups, .match = amba_match, .uevent = amba_uevent, + .dma_configure = platform_dma_configure, .pm = &amba_pm, - .force_dma = true, }; static int __init amba_init(void) diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c index d82566d6e237..f831a582209c 100644 --- a/drivers/base/dma-mapping.c +++ b/drivers/base/dma-mapping.c @@ -329,36 +329,13 @@ void dma_common_free_remap(void *cpu_addr, size_t size, unsigned long vm_flags) #endif /* - * Common configuration to enable DMA API use for a device + * enables DMA API use for a device */ -#include <linux/pci.h> - int dma_configure(struct device *dev) { - struct device *bridge = NULL, *dma_dev = dev; - enum dev_dma_attr attr; - int ret = 0; - - if (dev_is_pci(dev)) { - bridge = pci_get_host_bridge_device(to_pci_dev(dev)); - dma_dev = bridge; - if (IS_ENABLED(CONFIG_OF) && dma_dev->parent && - dma_dev->parent->of_node) - dma_dev = dma_dev->parent; - } - - if (dma_dev->of_node) { - ret = of_dma_configure(dev, dma_dev->of_node); - } else if (has_acpi_companion(dma_dev)) { - attr = acpi_get_dma_attr(to_acpi_device_node(dma_dev->fwnode)); - if (attr != DEV_DMA_NOT_SUPPORTED) - ret = acpi_dma_configure(dev, attr); - } - - if (bridge) - pci_put_host_bridge_device(bridge); - - return ret; + if (dev->bus->dma_configure) + return dev->bus->dma_configure(dev); + return 0; } void dma_deconfigure(struct device *dev) diff --git a/drivers/base/platform-msi.c b/drivers/base/platform-msi.c index 8e22073aeeed..60d6cc618f1c 100644 --- a/drivers/base/platform-msi.c +++ b/drivers/base/platform-msi.c @@ -101,6 +101,9 @@ static void platform_msi_update_chip_ops(struct msi_domain_info *info) chip->irq_set_affinity = msi_domain_set_affinity; if (!chip->irq_write_msi_msg) chip->irq_write_msi_msg = platform_msi_write_msg; + if (WARN_ON((info->flags & MSI_FLAG_LEVEL_CAPABLE) && + !(chip->flags & IRQCHIP_SUPPORTS_LEVEL_MSI))) + info->flags &= ~MSI_FLAG_LEVEL_CAPABLE; } static void platform_msi_free_descs(struct device *dev, int base, int nvec) diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 8075ddc70a17..c0ff1e73a634 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -1130,6 +1130,22 @@ int platform_pm_restore(struct device *dev) #endif /* CONFIG_HIBERNATE_CALLBACKS */ +int platform_dma_configure(struct device *dev) +{ + enum dev_dma_attr attr; + int ret = 0; + + if (dev->of_node) { + ret = of_dma_configure(dev, dev->of_node, true); + } else if (has_acpi_companion(dev)) { + attr = acpi_get_dma_attr(to_acpi_device_node(dev->fwnode)); + if (attr != DEV_DMA_NOT_SUPPORTED) + ret = acpi_dma_configure(dev, attr); + } + + return ret; +} + static const struct dev_pm_ops platform_dev_pm_ops = { .runtime_suspend = pm_generic_runtime_suspend, .runtime_resume = pm_generic_runtime_resume, @@ -1141,8 +1157,8 @@ struct bus_type platform_bus_type = { .dev_groups = platform_dev_groups, .match = platform_match, .uevent = platform_uevent, + .dma_configure = platform_dma_configure, .pm = &platform_dev_pm_ops, - .force_dma = true, }; EXPORT_SYMBOL_GPL(platform_bus_type); diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c index 5cadfd3394d8..8741fb5f8f54 100644 --- a/drivers/base/regmap/regmap-mmio.c +++ b/drivers/base/regmap/regmap-mmio.c @@ -206,7 +206,8 @@ static void regmap_mmio_free_context(void *context) if (!IS_ERR(ctx->clk)) { clk_unprepare(ctx->clk); - clk_put(ctx->clk); + if (!ctx->attached_clk) + clk_put(ctx->clk); } kfree(context); } diff --git a/drivers/base/regmap/regmap-slimbus.c b/drivers/base/regmap/regmap-slimbus.c index c90bee81d954..91d501eda8a9 100644 --- a/drivers/base/regmap/regmap-slimbus.c +++ b/drivers/base/regmap/regmap-slimbus.c @@ -41,7 +41,7 @@ static struct regmap_bus regmap_slimbus_bus = { static const struct regmap_bus *regmap_get_slimbus(struct slim_device *slim, const struct regmap_config *config) { - if (config->val_bits == 8 && config->reg_bits == 8) + if (config->val_bits == 8 && config->reg_bits == 16) return ®map_slimbus_bus; return ERR_PTR(-ENOTSUPP); diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index e6986c7608f1..fc1f4acdd189 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c @@ -207,7 +207,7 @@ static void bcma_of_fill_device(struct device *parent, core->irq = bcma_of_get_irq(parent, core, 0); - of_dma_configure(&core->dev, node); + of_dma_configure(&core->dev, node, false); } unsigned int bcma_core_irq(struct bcma_device *core, int num) diff --git a/drivers/bus/fsl-mc/fsl-mc-msi.c b/drivers/bus/fsl-mc/fsl-mc-msi.c index ec35e255b496..8b9c66d7c4ff 100644 --- a/drivers/bus/fsl-mc/fsl-mc-msi.c +++ b/drivers/bus/fsl-mc/fsl-mc-msi.c @@ -163,6 +163,8 @@ struct irq_domain *fsl_mc_msi_create_irq_domain(struct fwnode_handle *fwnode, { struct irq_domain *domain; + if (WARN_ON((info->flags & MSI_FLAG_LEVEL_CAPABLE))) + info->flags &= ~MSI_FLAG_LEVEL_CAPABLE; if (info->flags & MSI_FLAG_USE_DEF_DOM_OPS) fsl_mc_msi_update_dom_ops(info); if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS) diff --git a/drivers/char/random.c b/drivers/char/random.c index cd888d4ee605..a8fb0020ba5c 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -402,8 +402,7 @@ static struct poolinfo { /* * Static global variables */ -static DECLARE_WAIT_QUEUE_HEAD(random_read_wait); -static DECLARE_WAIT_QUEUE_HEAD(random_write_wait); +static DECLARE_WAIT_QUEUE_HEAD(random_wait); static struct fasync_struct *fasync; static DEFINE_SPINLOCK(random_ready_list_lock); @@ -722,8 +721,8 @@ retry: /* should we wake readers? */ if (entropy_bits >= random_read_wakeup_bits && - wq_has_sleeper(&random_read_wait)) { - wake_up_interruptible(&random_read_wait); + wq_has_sleeper(&random_wait)) { + wake_up_interruptible_poll(&random_wait, POLLIN); kill_fasync(&fasync, SIGIO, POLL_IN); } /* If the input pool is getting full, send some @@ -1397,7 +1396,7 @@ retry: trace_debit_entropy(r->name, 8 * ibytes); if (ibytes && (r->entropy_count >> ENTROPY_SHIFT) < random_write_wakeup_bits) { - wake_up_interruptible(&random_write_wait); + wake_up_interruptible_poll(&random_wait, POLLOUT); kill_fasync(&fasync, SIGIO, POLL_OUT); } @@ -1839,7 +1838,7 @@ _random_read(int nonblock, char __user *buf, size_t nbytes) if (nonblock) return -EAGAIN; - wait_event_interruptible(random_read_wait, + wait_event_interruptible(random_wait, ENTROPY_BITS(&input_pool) >= random_read_wakeup_bits); if (signal_pending(current)) @@ -1876,14 +1875,17 @@ urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) return ret; } +static struct wait_queue_head * +random_get_poll_head(struct file *file, __poll_t events) +{ + return &random_wait; +} + static __poll_t -random_poll(struct file *file, poll_table * wait) +random_poll_mask(struct file *file, __poll_t events) { - __poll_t mask; + __poll_t mask = 0; - poll_wait(file, &random_read_wait, wait); - poll_wait(file, &random_write_wait, wait); - mask = 0; if (ENTROPY_BITS(&input_pool) >= random_read_wakeup_bits) mask |= EPOLLIN | EPOLLRDNORM; if (ENTROPY_BITS(&input_pool) < random_write_wakeup_bits) @@ -1990,7 +1992,8 @@ static int random_fasync(int fd, struct file *filp, int on) const struct file_operations random_fops = { .read = random_read, .write = random_write, - .poll = random_poll, + .get_poll_head = random_get_poll_head, + .poll_mask = random_poll_mask, .unlocked_ioctl = random_ioctl, .fasync = random_fasync, .llseek = noop_llseek, @@ -2323,7 +2326,7 @@ void add_hwgenerator_randomness(const char *buffer, size_t count, * We'll be woken up again once below random_write_wakeup_thresh, * or when the calling thread is about to terminate. */ - wait_event_interruptible(random_write_wait, kthread_should_stop() || + wait_event_interruptible(random_wait, kthread_should_stop() || ENTROPY_BITS(&input_pool) <= random_write_wakeup_bits); mix_pool_bytes(poolp, buffer, count); credit_entropy_bits(poolp, entropy); diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 8e8a09755d10..dec0dd88ec15 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -450,8 +450,10 @@ config MTK_TIMER Support for Mediatek timer driver. config SPRD_TIMER - bool "Spreadtrum timer driver" if COMPILE_TEST + bool "Spreadtrum timer driver" if EXPERT depends on HAS_IOMEM + depends on (ARCH_SPRD || COMPILE_TEST) + default ARCH_SPRD select TIMER_OF help Enables support for the Spreadtrum timer driver. diff --git a/drivers/clocksource/arc_timer.c b/drivers/clocksource/arc_timer.c index 471b428d8034..20da9b1d7f7d 100644 --- a/drivers/clocksource/arc_timer.c +++ b/drivers/clocksource/arc_timer.c @@ -61,6 +61,20 @@ static u64 arc_read_gfrc(struct clocksource *cs) unsigned long flags; u32 l, h; + /* + * From a programming model pov, there seems to be just one instance of + * MCIP_CMD/MCIP_READBACK however micro-architecturally there's + * an instance PER ARC CORE (not per cluster), and there are dedicated + * hardware decode logic (per core) inside ARConnect to handle + * simultaneous read/write accesses from cores via those two registers. + * So several concurrent commands to ARConnect are OK if they are + * trying to access two different sub-components (like GFRC, + * inter-core interrupt, etc...). HW also supports simultaneously + * accessing GFRC by multiple cores. + * That's why it is safe to disable hard interrupts on the local CPU + * before access to GFRC instead of taking global MCIP spinlock + * defined in arch/arc/kernel/mcip.c + */ local_irq_save(flags); __mcip_cmd(CMD_GFRC_READ_LO, 0); diff --git a/drivers/clocksource/mips-gic-timer.c b/drivers/clocksource/mips-gic-timer.c index 986b6796b631..54f8a331b53a 100644 --- a/drivers/clocksource/mips-gic-timer.c +++ b/drivers/clocksource/mips-gic-timer.c @@ -5,6 +5,9 @@ * * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. */ + +#define pr_fmt(fmt) "mips-gic-timer: " fmt + #include <linux/clk.h> #include <linux/clockchips.h> #include <linux/cpu.h> @@ -136,8 +139,7 @@ static int gic_clockevent_init(void) ret = setup_percpu_irq(gic_timer_irq, &gic_compare_irqaction); if (ret < 0) { - pr_err("GIC timer IRQ %d setup failed: %d\n", - gic_timer_irq, ret); + pr_err("IRQ %d setup failed (%d)\n", gic_timer_irq, ret); return ret; } @@ -176,7 +178,7 @@ static int __init __gic_clocksource_init(void) ret = clocksource_register_hz(&gic_clocksource, gic_frequency); if (ret < 0) - pr_warn("GIC: Unable to register clocksource\n"); + pr_warn("Unable to register clocksource\n"); return ret; } @@ -188,7 +190,7 @@ static int __init gic_clocksource_of_init(struct device_node *node) if (!mips_gic_present() || !node->parent || !of_device_is_compatible(node->parent, "mti,gic")) { - pr_warn("No DT definition for the mips gic driver\n"); + pr_warn("No DT definition\n"); return -ENXIO; } @@ -196,7 +198,7 @@ static int __init gic_clocksource_of_init(struct device_node *node) if (!IS_ERR(clk)) { ret = clk_prepare_enable(clk); if (ret < 0) { - pr_err("GIC failed to enable clock\n"); + pr_err("Failed to enable clock\n"); clk_put(clk); return ret; } @@ -204,12 +206,12 @@ static int __init gic_clocksource_of_init(struct device_node *node) gic_frequency = clk_get_rate(clk); } else if (of_property_read_u32(node, "clock-frequency", &gic_frequency)) { - pr_err("GIC frequency not specified.\n"); + pr_err("Frequency not specified\n"); return -EINVAL; } gic_timer_irq = irq_of_parse_and_map(node, 0); if (!gic_timer_irq) { - pr_err("GIC timer IRQ not specified.\n"); + pr_err("IRQ not specified\n"); return -EINVAL; } @@ -220,7 +222,7 @@ static int __init gic_clocksource_of_init(struct device_node *node) ret = gic_clockevent_init(); if (!ret && !IS_ERR(clk)) { if (clk_notifier_register(clk, &gic_clk_nb) < 0) - pr_warn("GIC: Unable to register clock notifier\n"); + pr_warn("Unable to register clock notifier\n"); } /* And finally start the counter */ diff --git a/drivers/clocksource/mxs_timer.c b/drivers/clocksource/mxs_timer.c index a03434e9fe8f..f6ddae30933f 100644 --- a/drivers/clocksource/mxs_timer.c +++ b/drivers/clocksource/mxs_timer.c @@ -1,24 +1,10 @@ -/* - * Copyright (C) 2000-2001 Deep Blue Solutions - * Copyright (C) 2002 Shane Nay (shane@minirl.com) - * Copyright (C) 2006-2007 Pavel Pisa (ppisa@pikron.com) - * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de) - * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved. - * - * 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; either version 2 - * of the License, or (at your option) any later version. - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright (C) 2000-2001 Deep Blue Solutions +// Copyright (C) 2002 Shane Nay (shane@minirl.com) +// Copyright (C) 2006-2007 Pavel Pisa (ppisa@pikron.com) +// Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de) +// Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved. #include <linux/err.h> #include <linux/interrupt.h> diff --git a/drivers/clocksource/timer-imx-gpt.c b/drivers/clocksource/timer-imx-gpt.c index 6ec6d79b237c..165fbbb1c9a0 100644 --- a/drivers/clocksource/timer-imx-gpt.c +++ b/drivers/clocksource/timer-imx-gpt.c @@ -1,25 +1,9 @@ -/* - * linux/arch/arm/plat-mxc/time.c - * - * Copyright (C) 2000-2001 Deep Blue Solutions - * Copyright (C) 2002 Shane Nay (shane@minirl.com) - * Copyright (C) 2006-2007 Pavel Pisa (ppisa@pikron.com) - * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de) - * - * 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; either version 2 - * of the License, or (at your option) any later version. - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright (C) 2000-2001 Deep Blue Solutions +// Copyright (C) 2002 Shane Nay (shane@minirl.com) +// Copyright (C) 2006-2007 Pavel Pisa (ppisa@pikron.com) +// Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de) #include <linux/interrupt.h> #include <linux/irq.h> diff --git a/drivers/clocksource/timer-imx-tpm.c b/drivers/clocksource/timer-imx-tpm.c index 6c8318470b48..b7aa2b817078 100644 --- a/drivers/clocksource/timer-imx-tpm.c +++ b/drivers/clocksource/timer-imx-tpm.c @@ -1,12 +1,7 @@ -/* - * Copyright 2016 Freescale Semiconductor, Inc. - * Copyright 2017 NXP - * - * 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; either version 2 - * of the License, or (at your option) any later version. - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright 2016 Freescale Semiconductor, Inc. +// Copyright 2017 NXP #include <linux/clk.h> #include <linux/clockchips.h> diff --git a/drivers/dma/qcom/hidma_mgmt.c b/drivers/dma/qcom/hidma_mgmt.c index 000c7019ca7d..d64edeb6771a 100644 --- a/drivers/dma/qcom/hidma_mgmt.c +++ b/drivers/dma/qcom/hidma_mgmt.c @@ -398,7 +398,7 @@ static int __init hidma_mgmt_of_populate_channels(struct device_node *np) } of_node_get(child); new_pdev->dev.of_node = child; - of_dma_configure(&new_pdev->dev, child); + of_dma_configure(&new_pdev->dev, child, true); /* * It is assumed that calling of_msi_configure is safe on * platforms with or without MSI support. diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig index 3098410abad8..781a4a337557 100644 --- a/drivers/firmware/efi/Kconfig +++ b/drivers/firmware/efi/Kconfig @@ -174,6 +174,11 @@ config UEFI_CPER_ARM depends on UEFI_CPER && ( ARM || ARM64 ) default y +config UEFI_CPER_X86 + bool + depends on UEFI_CPER && X86 + default y + config EFI_DEV_PATH_PARSER bool depends on ACPI diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile index cb805374f4bc..5f9f5039de50 100644 --- a/drivers/firmware/efi/Makefile +++ b/drivers/firmware/efi/Makefile @@ -31,3 +31,4 @@ obj-$(CONFIG_ARM) += $(arm-obj-y) obj-$(CONFIG_ARM64) += $(arm-obj-y) obj-$(CONFIG_EFI_CAPSULE_LOADER) += capsule-loader.o obj-$(CONFIG_UEFI_CPER_ARM) += cper-arm.o +obj-$(CONFIG_UEFI_CPER_X86) += cper-x86.o diff --git a/drivers/firmware/efi/capsule-loader.c b/drivers/firmware/efi/capsule-loader.c index e456f4602df1..96688986da56 100644 --- a/drivers/firmware/efi/capsule-loader.c +++ b/drivers/firmware/efi/capsule-loader.c @@ -134,10 +134,16 @@ static ssize_t efi_capsule_submit_update(struct capsule_info *cap_info) /* Indicate capsule binary uploading is done */ cap_info->index = NO_FURTHER_WRITE_ACTION; - pr_info("Successfully upload capsule file with reboot type '%s'\n", - !cap_info->reset_type ? "RESET_COLD" : - cap_info->reset_type == 1 ? "RESET_WARM" : - "RESET_SHUTDOWN"); + + if (cap_info->header.flags & EFI_CAPSULE_PERSIST_ACROSS_RESET) { + pr_info("Successfully uploaded capsule file with reboot type '%s'\n", + !cap_info->reset_type ? "RESET_COLD" : + cap_info->reset_type == 1 ? "RESET_WARM" : + "RESET_SHUTDOWN"); + } else { + pr_info("Successfully processed capsule file\n"); + } + return 0; } diff --git a/drivers/firmware/efi/cper-arm.c b/drivers/firmware/efi/cper-arm.c index 698e5c8e0c8d..502811344e81 100644 --- a/drivers/firmware/efi/cper-arm.c +++ b/drivers/firmware/efi/cper-arm.c @@ -30,8 +30,6 @@ #include <acpi/ghes.h> #include <ras/ras_event.h> -#define INDENT_SP " " - static const char * const arm_reg_ctx_strs[] = { "AArch32 general purpose registers", "AArch32 EL1 context registers", @@ -283,7 +281,7 @@ void cper_print_proc_arm(const char *pfx, pfx, proc->psci_state); } - snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP); + snprintf(newpfx, sizeof(newpfx), "%s ", pfx); err_info = (struct cper_arm_err_info *)(proc + 1); for (i = 0; i < proc->err_info_num; i++) { @@ -310,7 +308,7 @@ void cper_print_proc_arm(const char *pfx, if (err_info->validation_bits & CPER_ARM_INFO_VALID_ERR_INFO) { printk("%serror_info: 0x%016llx\n", newpfx, err_info->error_info); - snprintf(infopfx, sizeof(infopfx), "%s%s", newpfx, INDENT_SP); + snprintf(infopfx, sizeof(infopfx), "%s ", newpfx); cper_print_arm_err_info(infopfx, err_info->type, err_info->error_info); } diff --git a/drivers/firmware/efi/cper-x86.c b/drivers/firmware/efi/cper-x86.c new file mode 100644 index 000000000000..2531de49f56c --- /dev/null +++ b/drivers/firmware/efi/cper-x86.c @@ -0,0 +1,356 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2018, Advanced Micro Devices, Inc. + +#include <linux/cper.h> + +/* + * We don't need a "CPER_IA" prefix since these are all locally defined. + * This will save us a lot of line space. + */ +#define VALID_LAPIC_ID BIT_ULL(0) +#define VALID_CPUID_INFO BIT_ULL(1) +#define VALID_PROC_ERR_INFO_NUM(bits) (((bits) & GENMASK_ULL(7, 2)) >> 2) +#define VALID_PROC_CXT_INFO_NUM(bits) (((bits) & GENMASK_ULL(13, 8)) >> 8) + +#define INFO_ERR_STRUCT_TYPE_CACHE \ + GUID_INIT(0xA55701F5, 0xE3EF, 0x43DE, 0xAC, 0x72, 0x24, 0x9B, \ + 0x57, 0x3F, 0xAD, 0x2C) +#define INFO_ERR_STRUCT_TYPE_TLB \ + GUID_INIT(0xFC06B535, 0x5E1F, 0x4562, 0x9F, 0x25, 0x0A, 0x3B, \ + 0x9A, 0xDB, 0x63, 0xC3) +#define INFO_ERR_STRUCT_TYPE_BUS \ + GUID_INIT(0x1CF3F8B3, 0xC5B1, 0x49a2, 0xAA, 0x59, 0x5E, 0xEF, \ + 0x92, 0xFF, 0xA6, 0x3C) +#define INFO_ERR_STRUCT_TYPE_MS \ + GUID_INIT(0x48AB7F57, 0xDC34, 0x4f6c, 0xA7, 0xD3, 0xB0, 0xB5, \ + 0xB0, 0xA7, 0x43, 0x14) + +#define INFO_VALID_CHECK_INFO BIT_ULL(0) +#define INFO_VALID_TARGET_ID BIT_ULL(1) +#define INFO_VALID_REQUESTOR_ID BIT_ULL(2) +#define INFO_VALID_RESPONDER_ID BIT_ULL(3) +#define INFO_VALID_IP BIT_ULL(4) + +#define CHECK_VALID_TRANS_TYPE BIT_ULL(0) +#define CHECK_VALID_OPERATION BIT_ULL(1) +#define CHECK_VALID_LEVEL BIT_ULL(2) +#define CHECK_VALID_PCC BIT_ULL(3) +#define CHECK_VALID_UNCORRECTED BIT_ULL(4) +#define CHECK_VALID_PRECISE_IP BIT_ULL(5) +#define CHECK_VALID_RESTARTABLE_IP BIT_ULL(6) +#define CHECK_VALID_OVERFLOW BIT_ULL(7) + +#define CHECK_VALID_BUS_PART_TYPE BIT_ULL(8) +#define CHECK_VALID_BUS_TIME_OUT BIT_ULL(9) +#define CHECK_VALID_BUS_ADDR_SPACE BIT_ULL(10) + +#define CHECK_VALID_BITS(check) (((check) & GENMASK_ULL(15, 0))) +#define CHECK_TRANS_TYPE(check) (((check) & GENMASK_ULL(17, 16)) >> 16) +#define CHECK_OPERATION(check) (((check) & GENMASK_ULL(21, 18)) >> 18) +#define CHECK_LEVEL(check) (((check) & GENMASK_ULL(24, 22)) >> 22) +#define CHECK_PCC BIT_ULL(25) +#define CHECK_UNCORRECTED BIT_ULL(26) +#define CHECK_PRECISE_IP BIT_ULL(27) +#define CHECK_RESTARTABLE_IP BIT_ULL(28) +#define CHECK_OVERFLOW BIT_ULL(29) + +#define CHECK_BUS_PART_TYPE(check) (((check) & GENMASK_ULL(31, 30)) >> 30) +#define CHECK_BUS_TIME_OUT BIT_ULL(32) +#define CHECK_BUS_ADDR_SPACE(check) (((check) & GENMASK_ULL(34, 33)) >> 33) + +#define CHECK_VALID_MS_ERR_TYPE BIT_ULL(0) +#define CHECK_VALID_MS_PCC BIT_ULL(1) +#define CHECK_VALID_MS_UNCORRECTED BIT_ULL(2) +#define CHECK_VALID_MS_PRECISE_IP BIT_ULL(3) +#define CHECK_VALID_MS_RESTARTABLE_IP BIT_ULL(4) +#define CHECK_VALID_MS_OVERFLOW BIT_ULL(5) + +#define CHECK_MS_ERR_TYPE(check) (((check) & GENMASK_ULL(18, 16)) >> 16) +#define CHECK_MS_PCC BIT_ULL(19) +#define CHECK_MS_UNCORRECTED BIT_ULL(20) +#define CHECK_MS_PRECISE_IP BIT_ULL(21) +#define CHECK_MS_RESTARTABLE_IP BIT_ULL(22) +#define CHECK_MS_OVERFLOW BIT_ULL(23) + +#define CTX_TYPE_MSR 1 +#define CTX_TYPE_MMREG 7 + +enum err_types { + ERR_TYPE_CACHE = 0, + ERR_TYPE_TLB, + ERR_TYPE_BUS, + ERR_TYPE_MS, + N_ERR_TYPES +}; + +static enum err_types cper_get_err_type(const guid_t *err_type) +{ + if (guid_equal(err_type, &INFO_ERR_STRUCT_TYPE_CACHE)) + return ERR_TYPE_CACHE; + else if (guid_equal(err_type, &INFO_ERR_STRUCT_TYPE_TLB)) + return ERR_TYPE_TLB; + else if (guid_equal(err_type, &INFO_ERR_STRUCT_TYPE_BUS)) + return ERR_TYPE_BUS; + else if (guid_equal(err_type, &INFO_ERR_STRUCT_TYPE_MS)) + return ERR_TYPE_MS; + else + return N_ERR_TYPES; +} + +static const char * const ia_check_trans_type_strs[] = { + "Instruction", + "Data Access", + "Generic", +}; + +static const char * const ia_check_op_strs[] = { + "generic error", + "generic read", + "generic write", + "data read", + "data write", + "instruction fetch", + "prefetch", + "eviction", + "snoop", +}; + +static const char * const ia_check_bus_part_type_strs[] = { + "Local Processor originated request", + "Local Processor responded to request", + "Local Processor observed", + "Generic", +}; + +static const char * const ia_check_bus_addr_space_strs[] = { + "Memory Access", + "Reserved", + "I/O", + "Other Transaction", +}; + +static const char * const ia_check_ms_error_type_strs[] = { + "No Error", + "Unclassified", + "Microcode ROM Parity Error", + "External Error", + "FRC Error", + "Internal Unclassified", +}; + +static const char * const ia_reg_ctx_strs[] = { + "Unclassified Data", + "MSR Registers (Machine Check and other MSRs)", + "32-bit Mode Execution Context", + "64-bit Mode Execution Context", + "FXSAVE Context", + "32-bit Mode Debug Registers (DR0-DR7)", + "64-bit Mode Debug Registers (DR0-DR7)", + "Memory Mapped Registers", +}; + +static inline void print_bool(char *str, const char *pfx, u64 check, u64 bit) +{ + printk("%s%s: %s\n", pfx, str, (check & bit) ? "true" : "false"); +} + +static void print_err_info_ms(const char *pfx, u16 validation_bits, u64 check) +{ + if (validation_bits & CHECK_VALID_MS_ERR_TYPE) { + u8 err_type = CHECK_MS_ERR_TYPE(check); + + printk("%sError Type: %u, %s\n", pfx, err_type, + err_type < ARRAY_SIZE(ia_check_ms_error_type_strs) ? + ia_check_ms_error_type_strs[err_type] : "unknown"); + } + + if (validation_bits & CHECK_VALID_MS_PCC) + print_bool("Processor Context Corrupt", pfx, check, CHECK_MS_PCC); + + if (validation_bits & CHECK_VALID_MS_UNCORRECTED) + print_bool("Uncorrected", pfx, check, CHECK_MS_UNCORRECTED); + + if (validation_bits & CHECK_VALID_MS_PRECISE_IP) + print_bool("Precise IP", pfx, check, CHECK_MS_PRECISE_IP); + + if (validation_bits & CHECK_VALID_MS_RESTARTABLE_IP) + print_bool("Restartable IP", pfx, check, CHECK_MS_RESTARTABLE_IP); + + if (validation_bits & CHECK_VALID_MS_OVERFLOW) + print_bool("Overflow", pfx, check, CHECK_MS_OVERFLOW); +} + +static void print_err_info(const char *pfx, u8 err_type, u64 check) +{ + u16 validation_bits = CHECK_VALID_BITS(check); + + /* + * The MS Check structure varies a lot from the others, so use a + * separate function for decoding. + */ + if (err_type == ERR_TYPE_MS) + return print_err_info_ms(pfx, validation_bits, check); + + if (validation_bits & CHECK_VALID_TRANS_TYPE) { + u8 trans_type = CHECK_TRANS_TYPE(check); + + printk("%sTransaction Type: %u, %s\n", pfx, trans_type, + trans_type < ARRAY_SIZE(ia_check_trans_type_strs) ? + ia_check_trans_type_strs[trans_type] : "unknown"); + } + + if (validation_bits & CHECK_VALID_OPERATION) { + u8 op = CHECK_OPERATION(check); + + /* + * CACHE has more operation types than TLB or BUS, though the + * name and the order are the same. + */ + u8 max_ops = (err_type == ERR_TYPE_CACHE) ? 9 : 7; + + printk("%sOperation: %u, %s\n", pfx, op, + op < max_ops ? ia_check_op_strs[op] : "unknown"); + } + + if (validation_bits & CHECK_VALID_LEVEL) + printk("%sLevel: %llu\n", pfx, CHECK_LEVEL(check)); + + if (validation_bits & CHECK_VALID_PCC) + print_bool("Processor Context Corrupt", pfx, check, CHECK_PCC); + + if (validation_bits & CHECK_VALID_UNCORRECTED) + print_bool("Uncorrected", pfx, check, CHECK_UNCORRECTED); + + if (validation_bits & CHECK_VALID_PRECISE_IP) + print_bool("Precise IP", pfx, check, CHECK_PRECISE_IP); + + if (validation_bits & CHECK_VALID_RESTARTABLE_IP) + print_bool("Restartable IP", pfx, check, CHECK_RESTARTABLE_IP); + + if (validation_bits & CHECK_VALID_OVERFLOW) + print_bool("Overflow", pfx, check, CHECK_OVERFLOW); + + if (err_type != ERR_TYPE_BUS) + return; + + if (validation_bits & CHECK_VALID_BUS_PART_TYPE) { + u8 part_type = CHECK_BUS_PART_TYPE(check); + + printk("%sParticipation Type: %u, %s\n", pfx, part_type, + part_type < ARRAY_SIZE(ia_check_bus_part_type_strs) ? + ia_check_bus_part_type_strs[part_type] : "unknown"); + } + + if (validation_bits & CHECK_VALID_BUS_TIME_OUT) + print_bool("Time Out", pfx, check, CHECK_BUS_TIME_OUT); + + if (validation_bits & CHECK_VALID_BUS_ADDR_SPACE) { + u8 addr_space = CHECK_BUS_ADDR_SPACE(check); + + printk("%sAddress Space: %u, %s\n", pfx, addr_space, + addr_space < ARRAY_SIZE(ia_check_bus_addr_space_strs) ? + ia_check_bus_addr_space_strs[addr_space] : "unknown"); + } +} + +void cper_print_proc_ia(const char *pfx, const struct cper_sec_proc_ia *proc) +{ + int i; + struct cper_ia_err_info *err_info; + struct cper_ia_proc_ctx *ctx_info; + char newpfx[64], infopfx[64]; + u8 err_type; + + if (proc->validation_bits & VALID_LAPIC_ID) + printk("%sLocal APIC_ID: 0x%llx\n", pfx, proc->lapic_id); + + if (proc->validation_bits & VALID_CPUID_INFO) { + printk("%sCPUID Info:\n", pfx); + print_hex_dump(pfx, "", DUMP_PREFIX_OFFSET, 16, 4, proc->cpuid, + sizeof(proc->cpuid), 0); + } + + snprintf(newpfx, sizeof(newpfx), "%s ", pfx); + + err_info = (struct cper_ia_err_info *)(proc + 1); + for (i = 0; i < VALID_PROC_ERR_INFO_NUM(proc->validation_bits); i++) { + printk("%sError Information Structure %d:\n", pfx, i); + + err_type = cper_get_err_type(&err_info->err_type); + printk("%sError Structure Type: %s\n", newpfx, + err_type < ARRAY_SIZE(cper_proc_error_type_strs) ? + cper_proc_error_type_strs[err_type] : "unknown"); + + if (err_type >= N_ERR_TYPES) { + printk("%sError Structure Type: %pUl\n", newpfx, + &err_info->err_type); + } + + if (err_info->validation_bits & INFO_VALID_CHECK_INFO) { + printk("%sCheck Information: 0x%016llx\n", newpfx, + err_info->check_info); + + if (err_type < N_ERR_TYPES) { + snprintf(infopfx, sizeof(infopfx), "%s ", + newpfx); + + print_err_info(infopfx, err_type, + err_info->check_info); + } + } + + if (err_info->validation_bits & INFO_VALID_TARGET_ID) { + printk("%sTarget Identifier: 0x%016llx\n", + newpfx, err_info->target_id); + } + + if (err_info->validation_bits & INFO_VALID_REQUESTOR_ID) { + printk("%sRequestor Identifier: 0x%016llx\n", + newpfx, err_info->requestor_id); + } + + if (err_info->validation_bits & INFO_VALID_RESPONDER_ID) { + printk("%sResponder Identifier: 0x%016llx\n", + newpfx, err_info->responder_id); + } + + if (err_info->validation_bits & INFO_VALID_IP) { + printk("%sInstruction Pointer: 0x%016llx\n", + newpfx, err_info->ip); + } + + err_info++; + } + + ctx_info = (struct cper_ia_proc_ctx *)err_info; + for (i = 0; i < VALID_PROC_CXT_INFO_NUM(proc->validation_bits); i++) { + int size = sizeof(*ctx_info) + ctx_info->reg_arr_size; + int groupsize = 4; + + printk("%sContext Information Structure %d:\n", pfx, i); + + printk("%sRegister Context Type: %s\n", newpfx, + ctx_info->reg_ctx_type < ARRAY_SIZE(ia_reg_ctx_strs) ? + ia_reg_ctx_strs[ctx_info->reg_ctx_type] : "unknown"); + + printk("%sRegister Array Size: 0x%04x\n", newpfx, + ctx_info->reg_arr_size); + + if (ctx_info->reg_ctx_type == CTX_TYPE_MSR) { + groupsize = 8; /* MSRs are 8 bytes wide. */ + printk("%sMSR Address: 0x%08x\n", newpfx, + ctx_info->msr_addr); + } + + if (ctx_info->reg_ctx_type == CTX_TYPE_MMREG) { + printk("%sMM Register Address: 0x%016llx\n", newpfx, + ctx_info->mm_reg_addr); + } + + printk("%sRegister Array:\n", newpfx); + print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, groupsize, + (ctx_info + 1), ctx_info->reg_arr_size, 0); + + ctx_info = (struct cper_ia_proc_ctx *)((long)ctx_info + size); + } +} diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c index c165933ebf38..3bf0dca378a6 100644 --- a/drivers/firmware/efi/cper.c +++ b/drivers/firmware/efi/cper.c @@ -37,8 +37,6 @@ #include <acpi/ghes.h> #include <ras/ras_event.h> -#define INDENT_SP " " - static char rcd_decode_str[CPER_REC_LEN]; /* @@ -433,7 +431,7 @@ cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT) printk("%s""fru_text: %.20s\n", pfx, gdata->fru_text); - snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP); + snprintf(newpfx, sizeof(newpfx), "%s ", pfx); if (guid_equal(sec_type, &CPER_SEC_PROC_GENERIC)) { struct cper_sec_proc_generic *proc_err = acpi_hest_get_payload(gdata); @@ -470,6 +468,16 @@ cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata else goto err_section_too_small; #endif +#if defined(CONFIG_UEFI_CPER_X86) + } else if (guid_equal(sec_type, &CPER_SEC_PROC_IA)) { + struct cper_sec_proc_ia *ia_err = acpi_hest_get_payload(gdata); + + printk("%ssection_type: IA32/X64 processor error\n", newpfx); + if (gdata->error_data_length >= sizeof(*ia_err)) + cper_print_proc_ia(newpfx, ia_err); + else + goto err_section_too_small; +#endif } else { const void *err = acpi_hest_get_payload(gdata); @@ -500,7 +508,7 @@ void cper_estatus_print(const char *pfx, "It has been corrected by h/w " "and requires no further action"); printk("%s""event severity: %s\n", pfx, cper_severity_str(severity)); - snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP); + snprintf(newpfx, sizeof(newpfx), "%s ", pfx); apei_estatus_for_each_section(estatus, gdata) { cper_estatus_print_section(newpfx, gdata, sec_no); diff --git a/drivers/firmware/efi/libstub/secureboot.c b/drivers/firmware/efi/libstub/secureboot.c index 8f07eb414c00..72d9dfbebf08 100644 --- a/drivers/firmware/efi/libstub/secureboot.c +++ b/drivers/firmware/efi/libstub/secureboot.c @@ -30,6 +30,9 @@ static const efi_char16_t shim_MokSBState_name[] = L"MokSBState"; /* * Determine whether we're in secure boot mode. + * + * Please keep the logic in sync with + * arch/x86/xen/efi.c:xen_efi_get_secureboot(). */ enum efi_secureboot_mode efi_get_secureboot(efi_system_table_t *sys_table_arg) { diff --git a/drivers/firmware/efi/libstub/tpm.c b/drivers/firmware/efi/libstub/tpm.c index 9d08cea3f1b0..caa37a6dd9d4 100644 --- a/drivers/firmware/efi/libstub/tpm.c +++ b/drivers/firmware/efi/libstub/tpm.c @@ -59,7 +59,7 @@ void efi_enable_reset_attack_mitigation(efi_system_table_t *sys_table_arg) #endif -void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg) +static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg) { efi_guid_t tcg2_guid = EFI_TCG2_PROTOCOL_GUID; efi_guid_t linux_eventlog_guid = LINUX_EFI_TPM_EVENT_LOG_GUID; diff --git a/drivers/gpu/host1x/bus.c b/drivers/gpu/host1x/bus.c index 88a3558b7916..815bdb42e3f0 100644 --- a/drivers/gpu/host1x/bus.c +++ b/drivers/gpu/host1x/bus.c @@ -314,6 +314,11 @@ static int host1x_device_match(struct device *dev, struct device_driver *drv) return strcmp(dev_name(dev), drv->name) == 0; } +static int host1x_dma_configure(struct device *dev) +{ + return of_dma_configure(dev, dev->of_node, true); +} + static const struct dev_pm_ops host1x_device_pm_ops = { .suspend = pm_generic_suspend, .resume = pm_generic_resume, @@ -326,8 +331,8 @@ static const struct dev_pm_ops host1x_device_pm_ops = { struct bus_type host1x_bus_type = { .name = "host1x", .match = host1x_device_match, + .dma_configure = host1x_dma_configure, .pm = &host1x_device_pm_ops, - .force_dma = true, }; static void __host1x_device_del(struct host1x_device *device) @@ -416,7 +421,7 @@ static int host1x_device_add(struct host1x *host1x, device->dev.bus = &host1x_bus_type; device->dev.parent = host1x->dev; - of_dma_configure(&device->dev, host1x->dev->of_node); + of_dma_configure(&device->dev, host1x->dev->of_node, true); err = host1x_device_parse_dt(device, driver); if (err < 0) { diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 6ec307c93ece..f10840ad465c 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -717,15 +717,12 @@ config SENSORS_LTC2945 be called ltc2945. config SENSORS_LTC2990 - tristate "Linear Technology LTC2990 (current monitoring mode only)" + tristate "Linear Technology LTC2990" depends on I2C help If you say yes here you get support for Linear Technology LTC2990 I2C System Monitor. The LTC2990 supports a combination of voltage, - current and temperature monitoring, but in addition to the Vcc supply - voltage and chip temperature, this driver currently only supports - reading two currents by measuring two differential voltages across - series resistors. + current and temperature monitoring. This driver can also be built as a module. If so, the module will be called ltc2990. diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c index 975c43d446f8..a6636fe42189 100644 --- a/drivers/hwmon/asus_atk0110.c +++ b/drivers/hwmon/asus_atk0110.c @@ -125,6 +125,8 @@ struct atk_data { int temperature_count; int fan_count; struct list_head sensor_list; + struct attribute_group attr_group; + const struct attribute_group *attr_groups[2]; struct { struct dentry *root; @@ -188,7 +190,6 @@ static int atk_add(struct acpi_device *device); static int atk_remove(struct acpi_device *device); static void atk_print_sensor(struct atk_data *data, union acpi_object *obj); static int atk_read_value(struct atk_sensor_data *sensor, u64 *value); -static void atk_free_sensors(struct atk_data *data); static struct acpi_driver atk_driver = { .name = ATK_HID, @@ -262,14 +263,6 @@ static ssize_t atk_limit2_show(struct device *dev, return sprintf(buf, "%lld\n", value); } -static ssize_t atk_name_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "atk0110\n"); -} -static struct device_attribute atk_name_attr = - __ATTR(name, 0444, atk_name_show, NULL); - static void atk_init_attribute(struct device_attribute *attr, char *name, sysfs_show_func show) { @@ -912,15 +905,13 @@ static int atk_add_sensor(struct atk_data *data, union acpi_object *obj) limit1 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT1); limit2 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT2); - sensor = kzalloc(sizeof(*sensor), GFP_KERNEL); + sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL); if (!sensor) return -ENOMEM; - sensor->acpi_name = kstrdup(name->string.pointer, GFP_KERNEL); - if (!sensor->acpi_name) { - err = -ENOMEM; - goto out; - } + sensor->acpi_name = devm_kstrdup(dev, name->string.pointer, GFP_KERNEL); + if (!sensor->acpi_name) + return -ENOMEM; INIT_LIST_HEAD(&sensor->list); sensor->type = type; @@ -961,9 +952,6 @@ static int atk_add_sensor(struct atk_data *data, union acpi_object *obj) (*num)++; return 1; -out: - kfree(sensor); - return err; } static int atk_enumerate_old_hwmon(struct atk_data *data) @@ -1004,8 +992,7 @@ static int atk_enumerate_old_hwmon(struct atk_data *data) dev_warn(dev, METHOD_OLD_ENUM_TMP ": ACPI exception: %s\n", acpi_format_exception(status)); - ret = -ENODEV; - goto cleanup; + return -ENODEV; } pack = buf.pointer; @@ -1026,8 +1013,7 @@ static int atk_enumerate_old_hwmon(struct atk_data *data) dev_warn(dev, METHOD_OLD_ENUM_FAN ": ACPI exception: %s\n", acpi_format_exception(status)); - ret = -ENODEV; - goto cleanup; + return -ENODEV; } pack = buf.pointer; @@ -1041,9 +1027,6 @@ static int atk_enumerate_old_hwmon(struct atk_data *data) ACPI_FREE(buf.pointer); return count; -cleanup: - atk_free_sensors(data); - return ret; } static int atk_ec_present(struct atk_data *data) @@ -1193,76 +1176,44 @@ static int atk_enumerate_new_hwmon(struct atk_data *data) return err; } -static int atk_create_files(struct atk_data *data) +static int atk_init_attribute_groups(struct atk_data *data) { + struct device *dev = &data->acpi_dev->dev; struct atk_sensor_data *s; - int err; + struct attribute **attrs; + int i = 0; + int len = (data->voltage_count + data->temperature_count + + data->fan_count) * 4 + 1; - list_for_each_entry(s, &data->sensor_list, list) { - err = device_create_file(data->hwmon_dev, &s->input_attr); - if (err) - return err; - err = device_create_file(data->hwmon_dev, &s->label_attr); - if (err) - return err; - err = device_create_file(data->hwmon_dev, &s->limit1_attr); - if (err) - return err; - err = device_create_file(data->hwmon_dev, &s->limit2_attr); - if (err) - return err; - } - - err = device_create_file(data->hwmon_dev, &atk_name_attr); - - return err; -} - -static void atk_remove_files(struct atk_data *data) -{ - struct atk_sensor_data *s; + attrs = devm_kcalloc(dev, len, sizeof(struct attribute *), GFP_KERNEL); + if (!attrs) + return -ENOMEM; list_for_each_entry(s, &data->sensor_list, list) { - device_remove_file(data->hwmon_dev, &s->input_attr); - device_remove_file(data->hwmon_dev, &s->label_attr); - device_remove_file(data->hwmon_dev, &s->limit1_attr); - device_remove_file(data->hwmon_dev, &s->limit2_attr); + attrs[i++] = &s->input_attr.attr; + attrs[i++] = &s->label_attr.attr; + attrs[i++] = &s->limit1_attr.attr; + attrs[i++] = &s->limit2_attr.attr; } - device_remove_file(data->hwmon_dev, &atk_name_attr); -} -static void atk_free_sensors(struct atk_data *data) -{ - struct list_head *head = &data->sensor_list; - struct atk_sensor_data *s, *tmp; + data->attr_group.attrs = attrs; + data->attr_groups[0] = &data->attr_group; - list_for_each_entry_safe(s, tmp, head, list) { - kfree(s->acpi_name); - kfree(s); - } + return 0; } static int atk_register_hwmon(struct atk_data *data) { struct device *dev = &data->acpi_dev->dev; - int err; dev_dbg(dev, "registering hwmon device\n"); - data->hwmon_dev = hwmon_device_register(dev); + data->hwmon_dev = hwmon_device_register_with_groups(dev, "atk0110", + data, + data->attr_groups); if (IS_ERR(data->hwmon_dev)) return PTR_ERR(data->hwmon_dev); - dev_dbg(dev, "populating sysfs directory\n"); - err = atk_create_files(data); - if (err) - goto remove; - return 0; -remove: - /* Cleanup the registered files */ - atk_remove_files(data); - hwmon_device_unregister(data->hwmon_dev); - return err; } static int atk_probe_if(struct atk_data *data) @@ -1350,7 +1301,7 @@ static int atk_add(struct acpi_device *device) dev_dbg(&device->dev, "adding...\n"); - data = kzalloc(sizeof(*data), GFP_KERNEL); + data = devm_kzalloc(&device->dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; @@ -1397,20 +1348,20 @@ static int atk_add(struct acpi_device *device) goto out; } + err = atk_init_attribute_groups(data); + if (err) + goto out; err = atk_register_hwmon(data); if (err) - goto cleanup; + goto out; atk_debugfs_init(data); device->driver_data = data; return 0; -cleanup: - atk_free_sensors(data); out: if (data->disable_ec) atk_ec_ctl(data, 0); - kfree(data); return err; } @@ -1423,8 +1374,6 @@ static int atk_remove(struct acpi_device *device) atk_debugfs_cleanup(data); - atk_remove_files(data); - atk_free_sensors(data); hwmon_device_unregister(data->hwmon_dev); if (data->disable_ec) { @@ -1432,8 +1381,6 @@ static int atk_remove(struct acpi_device *device) dev_err(&device->dev, "Failed to disable EC\n"); } - kfree(data); - return 0; } diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c index 5e78229ade04..22d3a84f13ef 100644 --- a/drivers/hwmon/fschmd.c +++ b/drivers/hwmon/fschmd.c @@ -105,7 +105,7 @@ static const u8 FSCHMD_REG_VOLT[7][6] = { static const int FSCHMD_NO_VOLT_SENSORS[7] = { 3, 3, 3, 3, 3, 3, 6 }; /* - * minimum pwm at which the fan is driven (pwm can by increased depending on + * minimum pwm at which the fan is driven (pwm can be increased depending on * the temp. Notice that for the scy some fans share there minimum speed. * Also notice that with the scy the sensor order is different than with the * other chips, this order was in the 2.4 driver and kept for consistency. diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index 32083e452cde..e88c01961948 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -698,6 +698,9 @@ hwmon_device_register_with_info(struct device *dev, const char *name, if (chip && (!chip->ops || !chip->ops->is_visible || !chip->info)) return ERR_PTR(-EINVAL); + if (chip && !dev) + return ERR_PTR(-EINVAL); + return __hwmon_device_register(dev, name, drvdata, chip, extra_groups); } EXPORT_SYMBOL_GPL(hwmon_device_register_with_info); diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c index 3b73dee6fdc6..17c6460ae351 100644 --- a/drivers/hwmon/k10temp.c +++ b/drivers/hwmon/k10temp.c @@ -37,6 +37,10 @@ MODULE_PARM_DESC(force, "force loading on processors with erratum 319"); /* Provide lock for writing to NB_SMU_IND_ADDR */ static DEFINE_MUTEX(nb_smu_ind_mutex); +#ifndef PCI_DEVICE_ID_AMD_15H_M70H_NB_F3 +#define PCI_DEVICE_ID_AMD_15H_M70H_NB_F3 0x15b3 +#endif + #ifndef PCI_DEVICE_ID_AMD_17H_DF_F3 #define PCI_DEVICE_ID_AMD_17H_DF_F3 0x1463 #endif @@ -81,6 +85,7 @@ struct k10temp_data { void (*read_tempreg)(struct pci_dev *pdev, u32 *regval); int temp_offset; u32 temp_adjust_mask; + bool show_tdie; }; struct tctl_offset { @@ -141,17 +146,24 @@ static void read_tempreg_nb_f17(struct pci_dev *pdev, u32 *regval) F17H_M01H_REPORTED_TEMP_CTRL_OFFSET, regval); } -static ssize_t temp1_input_show(struct device *dev, - struct device_attribute *attr, char *buf) +static unsigned int get_raw_temp(struct k10temp_data *data) { - struct k10temp_data *data = dev_get_drvdata(dev); - u32 regval; unsigned int temp; + u32 regval; data->read_tempreg(data->pdev, ®val); temp = (regval >> 21) * 125; if (regval & data->temp_adjust_mask) temp -= 49000; + return temp; +} + +static ssize_t temp1_input_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct k10temp_data *data = dev_get_drvdata(dev); + unsigned int temp = get_raw_temp(data); + if (temp > data->temp_offset) temp -= data->temp_offset; else @@ -160,6 +172,23 @@ static ssize_t temp1_input_show(struct device *dev, return sprintf(buf, "%u\n", temp); } +static ssize_t temp2_input_show(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct k10temp_data *data = dev_get_drvdata(dev); + unsigned int temp = get_raw_temp(data); + + return sprintf(buf, "%u\n", temp); +} + +static ssize_t temp_label_show(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + + return sprintf(buf, "%s\n", attr->index ? "Tctl" : "Tdie"); +} + static ssize_t temp1_max_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -187,16 +216,23 @@ static DEVICE_ATTR_RO(temp1_max); static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp_crit, NULL, 0); static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO, show_temp_crit, NULL, 1); +static SENSOR_DEVICE_ATTR(temp1_label, 0444, temp_label_show, NULL, 0); +static DEVICE_ATTR_RO(temp2_input); +static SENSOR_DEVICE_ATTR(temp2_label, 0444, temp_label_show, NULL, 1); + static umode_t k10temp_is_visible(struct kobject *kobj, struct attribute *attr, int index) { struct device *dev = container_of(kobj, struct device, kobj); struct k10temp_data *data = dev_get_drvdata(dev); struct pci_dev *pdev = data->pdev; + u32 reg; - if (index >= 2) { - u32 reg; - + switch (index) { + case 0 ... 1: /* temp1_input, temp1_max */ + default: + break; + case 2 ... 3: /* temp1_crit, temp1_crit_hyst */ if (!data->read_htcreg) return 0; @@ -208,6 +244,11 @@ static umode_t k10temp_is_visible(struct kobject *kobj, data->read_htcreg(data->pdev, ®); if (!(reg & HTC_ENABLE)) return 0; + break; + case 4 ... 6: /* temp1_label, temp2_input, temp2_label */ + if (!data->show_tdie) + return 0; + break; } return attr->mode; } @@ -217,6 +258,9 @@ static struct attribute *k10temp_attrs[] = { &dev_attr_temp1_max.attr, &sensor_dev_attr_temp1_crit.dev_attr.attr, &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_label.dev_attr.attr, + &dev_attr_temp2_input.attr, + &sensor_dev_attr_temp2_label.dev_attr.attr, NULL }; @@ -292,6 +336,7 @@ static int k10temp_probe(struct pci_dev *pdev, } else if (boot_cpu_data.x86 == 0x17) { data->temp_adjust_mask = 0x80000; data->read_tempreg = read_tempreg_nb_f17; + data->show_tdie = true; } else { data->read_htcreg = read_htcreg_pci; data->read_tempreg = read_tempreg_pci; @@ -320,6 +365,7 @@ static const struct pci_device_id k10temp_id_table[] = { { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M10H_F3) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F3) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M60H_NB_F3) }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M70H_NB_F3) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_NB_F3) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F3) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_DF_F3) }, diff --git a/drivers/hwmon/ltc2990.c b/drivers/hwmon/ltc2990.c index 8f8fe059ab48..2aefdc58b242 100644 --- a/drivers/hwmon/ltc2990.c +++ b/drivers/hwmon/ltc2990.c @@ -5,18 +5,16 @@ * Author: Mike Looijmans <mike.looijmans@topic.nl> * * License: GPLv2 - * - * This driver assumes the chip is wired as a dual current monitor, and - * reports the voltage drop across two series resistors. It also reports - * the chip's internal temperature and Vcc power supply voltage. */ +#include <linux/bitops.h> #include <linux/err.h> #include <linux/hwmon.h> #include <linux/hwmon-sysfs.h> #include <linux/i2c.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/of.h> #define LTC2990_STATUS 0x00 #define LTC2990_CONTROL 0x01 @@ -28,45 +26,108 @@ #define LTC2990_V4_MSB 0x0C #define LTC2990_VCC_MSB 0x0E -#define LTC2990_CONTROL_KELVIN BIT(7) -#define LTC2990_CONTROL_SINGLE BIT(6) -#define LTC2990_CONTROL_MEASURE_ALL (0x3 << 3) -#define LTC2990_CONTROL_MODE_CURRENT 0x06 -#define LTC2990_CONTROL_MODE_VOLTAGE 0x07 +#define LTC2990_IN0 BIT(0) +#define LTC2990_IN1 BIT(1) +#define LTC2990_IN2 BIT(2) +#define LTC2990_IN3 BIT(3) +#define LTC2990_IN4 BIT(4) +#define LTC2990_CURR1 BIT(5) +#define LTC2990_CURR2 BIT(6) +#define LTC2990_TEMP1 BIT(7) +#define LTC2990_TEMP2 BIT(8) +#define LTC2990_TEMP3 BIT(9) +#define LTC2990_NONE 0 +#define LTC2990_ALL GENMASK(9, 0) -/* convert raw register value to sign-extended integer in 16-bit range */ -static int ltc2990_voltage_to_int(int raw) -{ - if (raw & BIT(14)) - return -(0x4000 - (raw & 0x3FFF)) << 2; - else - return (raw & 0x3FFF) << 2; -} +#define LTC2990_MODE0_SHIFT 0 +#define LTC2990_MODE0_MASK GENMASK(2, 0) +#define LTC2990_MODE1_SHIFT 3 +#define LTC2990_MODE1_MASK GENMASK(1, 0) + +/* Enabled measurements for mode bits 2..0 */ +static const int ltc2990_attrs_ena_0[] = { + LTC2990_IN1 | LTC2990_IN2 | LTC2990_TEMP3, + LTC2990_CURR1 | LTC2990_TEMP3, + LTC2990_CURR1 | LTC2990_IN3 | LTC2990_IN4, + LTC2990_TEMP2 | LTC2990_IN3 | LTC2990_IN4, + LTC2990_TEMP2 | LTC2990_CURR2, + LTC2990_TEMP2 | LTC2990_TEMP3, + LTC2990_CURR1 | LTC2990_CURR2, + LTC2990_IN1 | LTC2990_IN2 | LTC2990_IN3 | LTC2990_IN4 +}; + +/* Enabled measurements for mode bits 4..3 */ +static const int ltc2990_attrs_ena_1[] = { + LTC2990_NONE, + LTC2990_TEMP2 | LTC2990_IN1 | LTC2990_CURR1, + LTC2990_TEMP3 | LTC2990_IN3 | LTC2990_CURR2, + LTC2990_ALL +}; + +struct ltc2990_data { + struct i2c_client *i2c; + u32 mode[2]; +}; /* Return the converted value from the given register in uV or mC */ -static int ltc2990_get_value(struct i2c_client *i2c, u8 reg, int *result) +static int ltc2990_get_value(struct i2c_client *i2c, int index, int *result) { int val; + u8 reg; + + switch (index) { + case LTC2990_IN0: + reg = LTC2990_VCC_MSB; + break; + case LTC2990_IN1: + case LTC2990_CURR1: + case LTC2990_TEMP2: + reg = LTC2990_V1_MSB; + break; + case LTC2990_IN2: + reg = LTC2990_V2_MSB; + break; + case LTC2990_IN3: + case LTC2990_CURR2: + case LTC2990_TEMP3: + reg = LTC2990_V3_MSB; + break; + case LTC2990_IN4: + reg = LTC2990_V4_MSB; + break; + case LTC2990_TEMP1: + reg = LTC2990_TINT_MSB; + break; + default: + return -EINVAL; + } val = i2c_smbus_read_word_swapped(i2c, reg); if (unlikely(val < 0)) return val; - switch (reg) { - case LTC2990_TINT_MSB: - /* internal temp, 0.0625 degrees/LSB, 13-bit */ - val = (val & 0x1FFF) << 3; - *result = (val * 1000) >> 7; + switch (index) { + case LTC2990_TEMP1: + case LTC2990_TEMP2: + case LTC2990_TEMP3: + /* temp, 0.0625 degrees/LSB */ + *result = sign_extend32(val, 12) * 1000 / 16; break; - case LTC2990_V1_MSB: - case LTC2990_V3_MSB: - /* Vx-Vy, 19.42uV/LSB. Depends on mode. */ - *result = ltc2990_voltage_to_int(val) * 1942 / (4 * 100); + case LTC2990_CURR1: + case LTC2990_CURR2: + /* Vx-Vy, 19.42uV/LSB */ + *result = sign_extend32(val, 14) * 1942 / 100; break; - case LTC2990_VCC_MSB: - /* Vcc, 305.18ÎĽV/LSB, 2.5V offset */ - *result = (ltc2990_voltage_to_int(val) * 30518 / - (4 * 100 * 1000)) + 2500; + case LTC2990_IN0: + /* Vcc, 305.18uV/LSB, 2.5V offset */ + *result = sign_extend32(val, 14) * 30518 / (100 * 1000) + 2500; + break; + case LTC2990_IN1: + case LTC2990_IN2: + case LTC2990_IN3: + case LTC2990_IN4: + /* Vx, 305.18uV/LSB */ + *result = sign_extend32(val, 14) * 30518 / (100 * 1000); break; default: return -EINVAL; /* won't happen, keep compiler happy */ @@ -79,48 +140,117 @@ static ssize_t ltc2990_show_value(struct device *dev, struct device_attribute *da, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct ltc2990_data *data = dev_get_drvdata(dev); int value; int ret; - ret = ltc2990_get_value(dev_get_drvdata(dev), attr->index, &value); + ret = ltc2990_get_value(data->i2c, attr->index, &value); if (unlikely(ret < 0)) return ret; return snprintf(buf, PAGE_SIZE, "%d\n", value); } +static umode_t ltc2990_attrs_visible(struct kobject *kobj, + struct attribute *a, int n) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct ltc2990_data *data = dev_get_drvdata(dev); + struct device_attribute *da = + container_of(a, struct device_attribute, attr); + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + + int attrs_mask = LTC2990_IN0 | LTC2990_TEMP1 | + (ltc2990_attrs_ena_0[data->mode[0]] & + ltc2990_attrs_ena_1[data->mode[1]]); + + if (attr->index & attrs_mask) + return a->mode; + + return 0; +} + static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, ltc2990_show_value, NULL, - LTC2990_TINT_MSB); + LTC2990_TEMP1); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, ltc2990_show_value, NULL, + LTC2990_TEMP2); +static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, ltc2990_show_value, NULL, + LTC2990_TEMP3); static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc2990_show_value, NULL, - LTC2990_V1_MSB); + LTC2990_CURR1); static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO, ltc2990_show_value, NULL, - LTC2990_V3_MSB); + LTC2990_CURR2); static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ltc2990_show_value, NULL, - LTC2990_VCC_MSB); + LTC2990_IN0); +static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc2990_show_value, NULL, + LTC2990_IN1); +static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc2990_show_value, NULL, + LTC2990_IN2); +static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, ltc2990_show_value, NULL, + LTC2990_IN3); +static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, ltc2990_show_value, NULL, + LTC2990_IN4); static struct attribute *ltc2990_attrs[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp3_input.dev_attr.attr, &sensor_dev_attr_curr1_input.dev_attr.attr, &sensor_dev_attr_curr2_input.dev_attr.attr, &sensor_dev_attr_in0_input.dev_attr.attr, + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in3_input.dev_attr.attr, + &sensor_dev_attr_in4_input.dev_attr.attr, NULL, }; -ATTRIBUTE_GROUPS(ltc2990); + +static const struct attribute_group ltc2990_group = { + .attrs = ltc2990_attrs, + .is_visible = ltc2990_attrs_visible, +}; +__ATTRIBUTE_GROUPS(ltc2990); static int ltc2990_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { int ret; struct device *hwmon_dev; + struct ltc2990_data *data; + struct device_node *of_node = i2c->dev.of_node; if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) return -ENODEV; - /* Setup continuous mode, current monitor */ + data = devm_kzalloc(&i2c->dev, sizeof(struct ltc2990_data), GFP_KERNEL); + if (unlikely(!data)) + return -ENOMEM; + + data->i2c = i2c; + + if (of_node) { + ret = of_property_read_u32_array(of_node, "lltc,meas-mode", + data->mode, 2); + if (ret < 0) + return ret; + + if (data->mode[0] & ~LTC2990_MODE0_MASK || + data->mode[1] & ~LTC2990_MODE1_MASK) + return -EINVAL; + } else { + ret = i2c_smbus_read_byte_data(i2c, LTC2990_CONTROL); + if (ret < 0) + return ret; + + data->mode[0] = ret >> LTC2990_MODE0_SHIFT & LTC2990_MODE0_MASK; + data->mode[1] = ret >> LTC2990_MODE1_SHIFT & LTC2990_MODE1_MASK; + } + + /* Setup continuous mode */ ret = i2c_smbus_write_byte_data(i2c, LTC2990_CONTROL, - LTC2990_CONTROL_MEASURE_ALL | - LTC2990_CONTROL_MODE_CURRENT); + data->mode[0] << LTC2990_MODE0_SHIFT | + data->mode[1] << LTC2990_MODE1_SHIFT); if (ret < 0) { dev_err(&i2c->dev, "Error: Failed to set control mode.\n"); return ret; @@ -134,7 +264,7 @@ static int ltc2990_i2c_probe(struct i2c_client *i2c, hwmon_dev = devm_hwmon_device_register_with_groups(&i2c->dev, i2c->name, - i2c, + data, ltc2990_groups); return PTR_ERR_OR_ZERO(hwmon_dev); diff --git a/drivers/hwmon/mc13783-adc.c b/drivers/hwmon/mc13783-adc.c index 960a1db6f269..67860ad2e3d9 100644 --- a/drivers/hwmon/mc13783-adc.c +++ b/drivers/hwmon/mc13783-adc.c @@ -63,6 +63,10 @@ static int mc13783_adc_read(struct device *dev, if (ret) return ret; + /* ADIN7 subchannels */ + if (channel >= 16) + channel = 7; + channel &= 0x7; *val = (sample[channel % 4] >> (channel > 3 ? 14 : 2)) & 0x3ff; @@ -111,6 +115,57 @@ static ssize_t mc13783_adc_read_gp(struct device *dev, return sprintf(buf, "%u\n", val); } +static ssize_t mc13783_adc_read_uid(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + unsigned int val; + struct platform_device *pdev = to_platform_device(dev); + kernel_ulong_t driver_data = platform_get_device_id(pdev)->driver_data; + int ret = mc13783_adc_read(dev, devattr, &val); + + if (ret) + return ret; + + if (driver_data & MC13783_ADC_BPDIV2) + /* MC13892 have 1/2 divider, input range is [0, 4.800V] */ + val = DIV_ROUND_CLOSEST(val * 4800, 1024); + else + /* MC13783 have 0.9 divider, input range is [0, 2.555V] */ + val = DIV_ROUND_CLOSEST(val * 2555, 1024); + + return sprintf(buf, "%u\n", val); +} + +static ssize_t mc13783_adc_read_temp(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + unsigned int val; + struct platform_device *pdev = to_platform_device(dev); + kernel_ulong_t driver_data = platform_get_device_id(pdev)->driver_data; + int ret = mc13783_adc_read(dev, devattr, &val); + + if (ret) + return ret; + + if (driver_data & MC13783_ADC_BPDIV2) { + /* + * MC13892: + * Die Temperature Read Out Code at 25C 680 + * Temperature change per LSB +0.4244C + */ + ret = DIV_ROUND_CLOSEST(-2635920 + val * 4244, 10); + } else { + /* + * MC13783: + * Die Temperature Read Out Code at 25C 282 + * Temperature change per LSB -1.14C + */ + ret = 346480 - 1140 * val; + } + + return sprintf(buf, "%d\n", ret); +} + static DEVICE_ATTR_RO(name); static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, mc13783_adc_read_bp, NULL, 2); static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, mc13783_adc_read_gp, NULL, 5); @@ -124,6 +179,9 @@ static SENSOR_DEVICE_ATTR(in12_input, S_IRUGO, mc13783_adc_read_gp, NULL, 12); static SENSOR_DEVICE_ATTR(in13_input, S_IRUGO, mc13783_adc_read_gp, NULL, 13); static SENSOR_DEVICE_ATTR(in14_input, S_IRUGO, mc13783_adc_read_gp, NULL, 14); static SENSOR_DEVICE_ATTR(in15_input, S_IRUGO, mc13783_adc_read_gp, NULL, 15); +static SENSOR_DEVICE_ATTR(in16_input, S_IRUGO, mc13783_adc_read_uid, NULL, 16); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, + mc13783_adc_read_temp, NULL, 17); static struct attribute *mc13783_attr_base[] = { &dev_attr_name.attr, @@ -131,6 +189,8 @@ static struct attribute *mc13783_attr_base[] = { &sensor_dev_attr_in5_input.dev_attr.attr, &sensor_dev_attr_in6_input.dev_attr.attr, &sensor_dev_attr_in7_input.dev_attr.attr, + &sensor_dev_attr_in16_input.dev_attr.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, NULL }; diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c index 54d4d78ca46a..6f344654ef22 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/ide-dma.c @@ -180,7 +180,6 @@ EXPORT_SYMBOL_GPL(ide_dma_unmap_sg); void ide_dma_off_quietly(ide_drive_t *drive) { drive->dev_flags &= ~IDE_DFLAG_USING_DMA; - ide_toggle_bounce(drive, 0); drive->hwif->dma_ops->dma_host_set(drive, 0); } @@ -211,7 +210,6 @@ EXPORT_SYMBOL(ide_dma_off); void ide_dma_on(ide_drive_t *drive) { drive->dev_flags |= IDE_DFLAG_USING_DMA; - ide_toggle_bounce(drive, 1); drive->hwif->dma_ops->dma_host_set(drive, 1); } diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c index e1180fa46196..78cb79eddc8b 100644 --- a/drivers/ide/ide-lib.c +++ b/drivers/ide/ide-lib.c @@ -6,32 +6,6 @@ #include <linux/ide.h> #include <linux/bitops.h> -/** - * ide_toggle_bounce - handle bounce buffering - * @drive: drive to update - * @on: on/off boolean - * - * Enable or disable bounce buffering for the device. Drives move - * between PIO and DMA and that changes the rules we need. - */ - -void ide_toggle_bounce(ide_drive_t *drive, int on) -{ - u64 addr = BLK_BOUNCE_HIGH; /* dma64_addr_t */ - - if (!PCI_DMA_BUS_IS_PHYS) { - addr = BLK_BOUNCE_ANY; - } else if (on && drive->media == ide_disk) { - struct device *dev = drive->hwif->dev; - - if (dev && dev->dma_mask) - addr = *dev->dma_mask; - } - - if (drive->queue) - blk_queue_bounce_limit(drive->queue, addr); -} - u64 ide_get_lba_addr(struct ide_cmd *cmd, int lba48) { struct ide_taskfile *tf = &cmd->tf; diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 2019e66eada7..56d7bc228cb3 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -796,8 +796,7 @@ static int ide_init_queue(ide_drive_t *drive) * This will be fixed once we teach pci_map_sg() about our boundary * requirements, hopefully soon. *FIXME* */ - if (!PCI_DMA_BUS_IS_PHYS) - max_sg_entries >>= 1; + max_sg_entries >>= 1; #endif /* CONFIG_PCI */ blk_queue_max_segments(q, max_sg_entries); @@ -805,9 +804,6 @@ static int ide_init_queue(ide_drive_t *drive) /* assign drive queue */ drive->queue = q; - /* needs drive->queue to be set */ - ide_toggle_bounce(drive, 1); - return 0; } diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index df171cb85822..5b714a062fa7 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -146,6 +146,7 @@ config INTEL_IOMMU select DMA_DIRECT_OPS select IOMMU_API select IOMMU_IOVA + select NEED_DMA_MAP_STATE select DMAR_TABLE help DMA remapping (DMAR) devices support enables independent address diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 5ed465ab1c76..15f268f646bf 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -27,7 +27,7 @@ obj-$(CONFIG_ARM_GIC) += irq-gic.o irq-gic-common.o obj-$(CONFIG_ARM_GIC_PM) += irq-gic-pm.o obj-$(CONFIG_ARCH_REALVIEW) += irq-gic-realview.o obj-$(CONFIG_ARM_GIC_V2M) += irq-gic-v2m.o -obj-$(CONFIG_ARM_GIC_V3) += irq-gic-v3.o irq-gic-common.o +obj-$(CONFIG_ARM_GIC_V3) += irq-gic-v3.o irq-gic-v3-mbi.o irq-gic-common.o obj-$(CONFIG_ARM_GIC_V3_ITS) += irq-gic-v3-its.o irq-gic-v3-its-platform-msi.o irq-gic-v4.o obj-$(CONFIG_ARM_GIC_V3_ITS_PCI) += irq-gic-v3-its-pci-msi.o obj-$(CONFIG_ARM_GIC_V3_ITS_FSL_MC) += irq-gic-v3-its-fsl-mc-msi.o diff --git a/drivers/irqchip/irq-gic-v3-mbi.c b/drivers/irqchip/irq-gic-v3-mbi.c new file mode 100644 index 000000000000..ad70e7c416e3 --- /dev/null +++ b/drivers/irqchip/irq-gic-v3-mbi.c @@ -0,0 +1,331 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 ARM Limited, All Rights Reserved. + * Author: Marc Zyngier <marc.zyngier@arm.com> + */ + +#define pr_fmt(fmt) "GICv3: " fmt + +#include <linux/dma-iommu.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> +#include <linux/kernel.h> +#include <linux/msi.h> +#include <linux/of_address.h> +#include <linux/of_pci.h> +#include <linux/slab.h> +#include <linux/spinlock.h> + +#include <linux/irqchip/arm-gic-v3.h> + +struct mbi_range { + u32 spi_start; + u32 nr_spis; + unsigned long *bm; +}; + +static struct mutex mbi_lock; +static phys_addr_t mbi_phys_base; +static struct mbi_range *mbi_ranges; +static unsigned int mbi_range_nr; + +static struct irq_chip mbi_irq_chip = { + .name = "MBI", + .irq_mask = irq_chip_mask_parent, + .irq_unmask = irq_chip_unmask_parent, + .irq_eoi = irq_chip_eoi_parent, + .irq_set_type = irq_chip_set_type_parent, + .irq_set_affinity = irq_chip_set_affinity_parent, +}; + +static int mbi_irq_gic_domain_alloc(struct irq_domain *domain, + unsigned int virq, + irq_hw_number_t hwirq) +{ + struct irq_fwspec fwspec; + struct irq_data *d; + int err; + + /* + * Using ACPI? There is no MBI support in the spec, you + * shouldn't even be here. + */ + if (!is_of_node(domain->parent->fwnode)) + return -EINVAL; + + /* + * Let's default to edge. This is consistent with traditional + * MSIs, and systems requiring level signaling will just + * enforce the trigger on their own. + */ + fwspec.fwnode = domain->parent->fwnode; + fwspec.param_count = 3; + fwspec.param[0] = 0; + fwspec.param[1] = hwirq - 32; + fwspec.param[2] = IRQ_TYPE_EDGE_RISING; + + err = irq_domain_alloc_irqs_parent(domain, virq, 1, &fwspec); + if (err) + return err; + + d = irq_domain_get_irq_data(domain->parent, virq); + return d->chip->irq_set_type(d, IRQ_TYPE_EDGE_RISING); +} + +static void mbi_free_msi(struct mbi_range *mbi, unsigned int hwirq, + int nr_irqs) +{ + mutex_lock(&mbi_lock); + bitmap_release_region(mbi->bm, hwirq - mbi->spi_start, + get_count_order(nr_irqs)); + mutex_unlock(&mbi_lock); +} + +static int mbi_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, + unsigned int nr_irqs, void *args) +{ + struct mbi_range *mbi = NULL; + int hwirq, offset, i, err = 0; + + mutex_lock(&mbi_lock); + for (i = 0; i < mbi_range_nr; i++) { + offset = bitmap_find_free_region(mbi_ranges[i].bm, + mbi_ranges[i].nr_spis, + get_count_order(nr_irqs)); + if (offset >= 0) { + mbi = &mbi_ranges[i]; + break; + } + } + mutex_unlock(&mbi_lock); + + if (!mbi) + return -ENOSPC; + + hwirq = mbi->spi_start + offset; + + for (i = 0; i < nr_irqs; i++) { + err = mbi_irq_gic_domain_alloc(domain, virq + i, hwirq + i); + if (err) + goto fail; + + irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i, + &mbi_irq_chip, mbi); + } + + return 0; + +fail: + irq_domain_free_irqs_parent(domain, virq, nr_irqs); + mbi_free_msi(mbi, hwirq, nr_irqs); + return err; +} + +static void mbi_irq_domain_free(struct irq_domain *domain, + unsigned int virq, unsigned int nr_irqs) +{ + struct irq_data *d = irq_domain_get_irq_data(domain, virq); + struct mbi_range *mbi = irq_data_get_irq_chip_data(d); + + mbi_free_msi(mbi, d->hwirq, nr_irqs); + irq_domain_free_irqs_parent(domain, virq, nr_irqs); +} + +static const struct irq_domain_ops mbi_domain_ops = { + .alloc = mbi_irq_domain_alloc, + .free = mbi_irq_domain_free, +}; + +static void mbi_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) +{ + msg[0].address_hi = upper_32_bits(mbi_phys_base + GICD_SETSPI_NSR); + msg[0].address_lo = lower_32_bits(mbi_phys_base + GICD_SETSPI_NSR); + msg[0].data = data->parent_data->hwirq; + + iommu_dma_map_msi_msg(data->irq, msg); +} + +#ifdef CONFIG_PCI_MSI +/* PCI-specific irqchip */ +static void mbi_mask_msi_irq(struct irq_data *d) +{ + pci_msi_mask_irq(d); + irq_chip_mask_parent(d); +} + +static void mbi_unmask_msi_irq(struct irq_data *d) +{ + pci_msi_unmask_irq(d); + irq_chip_unmask_parent(d); +} + +static struct irq_chip mbi_msi_irq_chip = { + .name = "MSI", + .irq_mask = mbi_mask_msi_irq, + .irq_unmask = mbi_unmask_msi_irq, + .irq_eoi = irq_chip_eoi_parent, + .irq_compose_msi_msg = mbi_compose_msi_msg, + .irq_write_msi_msg = pci_msi_domain_write_msg, +}; + +static struct msi_domain_info mbi_msi_domain_info = { + .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | + MSI_FLAG_PCI_MSIX | MSI_FLAG_MULTI_PCI_MSI), + .chip = &mbi_msi_irq_chip, +}; + +static int mbi_allocate_pci_domain(struct irq_domain *nexus_domain, + struct irq_domain **pci_domain) +{ + *pci_domain = pci_msi_create_irq_domain(nexus_domain->parent->fwnode, + &mbi_msi_domain_info, + nexus_domain); + if (!*pci_domain) + return -ENOMEM; + + return 0; +} +#else +static int mbi_allocate_pci_domain(struct irq_domain *nexus_domain, + struct irq_domain **pci_domain) +{ + *pci_domain = NULL; + return 0; +} +#endif + +static void mbi_compose_mbi_msg(struct irq_data *data, struct msi_msg *msg) +{ + mbi_compose_msi_msg(data, msg); + + msg[1].address_hi = upper_32_bits(mbi_phys_base + GICD_CLRSPI_NSR); + msg[1].address_lo = lower_32_bits(mbi_phys_base + GICD_CLRSPI_NSR); + msg[1].data = data->parent_data->hwirq; + + iommu_dma_map_msi_msg(data->irq, &msg[1]); +} + +/* Platform-MSI specific irqchip */ +static struct irq_chip mbi_pmsi_irq_chip = { + .name = "pMSI", + .irq_set_type = irq_chip_set_type_parent, + .irq_compose_msi_msg = mbi_compose_mbi_msg, + .flags = IRQCHIP_SUPPORTS_LEVEL_MSI, +}; + +static struct msi_domain_ops mbi_pmsi_ops = { +}; + +static struct msi_domain_info mbi_pmsi_domain_info = { + .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | + MSI_FLAG_LEVEL_CAPABLE), + .ops = &mbi_pmsi_ops, + .chip = &mbi_pmsi_irq_chip, +}; + +static int mbi_allocate_domains(struct irq_domain *parent) +{ + struct irq_domain *nexus_domain, *pci_domain, *plat_domain; + int err; + + nexus_domain = irq_domain_create_tree(parent->fwnode, + &mbi_domain_ops, NULL); + if (!nexus_domain) + return -ENOMEM; + + irq_domain_update_bus_token(nexus_domain, DOMAIN_BUS_NEXUS); + nexus_domain->parent = parent; + + err = mbi_allocate_pci_domain(nexus_domain, &pci_domain); + + plat_domain = platform_msi_create_irq_domain(parent->fwnode, + &mbi_pmsi_domain_info, + nexus_domain); + + if (err || !plat_domain) { + if (plat_domain) + irq_domain_remove(plat_domain); + if (pci_domain) + irq_domain_remove(pci_domain); + irq_domain_remove(nexus_domain); + return -ENOMEM; + } + + return 0; +} + +int __init mbi_init(struct fwnode_handle *fwnode, struct irq_domain *parent) +{ + struct device_node *np; + const __be32 *reg; + int ret, n; + + np = to_of_node(fwnode); + + if (!of_property_read_bool(np, "msi-controller")) + return 0; + + n = of_property_count_elems_of_size(np, "mbi-ranges", sizeof(u32)); + if (n <= 0 || n % 2) + return -EINVAL; + + mbi_range_nr = n / 2; + mbi_ranges = kcalloc(mbi_range_nr, sizeof(*mbi_ranges), GFP_KERNEL); + if (!mbi_ranges) + return -ENOMEM; + + for (n = 0; n < mbi_range_nr; n++) { + ret = of_property_read_u32_index(np, "mbi-ranges", n * 2, + &mbi_ranges[n].spi_start); + if (ret) + goto err_free_mbi; + ret = of_property_read_u32_index(np, "mbi-ranges", n * 2 + 1, + &mbi_ranges[n].nr_spis); + if (ret) + goto err_free_mbi; + + mbi_ranges[n].bm = kcalloc(BITS_TO_LONGS(mbi_ranges[n].nr_spis), + sizeof(long), GFP_KERNEL); + if (!mbi_ranges[n].bm) { + ret = -ENOMEM; + goto err_free_mbi; + } + pr_info("MBI range [%d:%d]\n", mbi_ranges[n].spi_start, + mbi_ranges[n].spi_start + mbi_ranges[n].nr_spis - 1); + } + + reg = of_get_property(np, "mbi-alias", NULL); + if (reg) { + mbi_phys_base = of_translate_address(np, reg); + if (mbi_phys_base == OF_BAD_ADDR) { + ret = -ENXIO; + goto err_free_mbi; + } + } else { + struct resource res; + + if (of_address_to_resource(np, 0, &res)) { + ret = -ENXIO; + goto err_free_mbi; + } + + mbi_phys_base = res.start; + } + + pr_info("Using MBI frame %pa\n", &mbi_phys_base); + + ret = mbi_allocate_domains(parent); + if (ret) + goto err_free_mbi; + + return 0; + +err_free_mbi: + if (mbi_ranges) { + for (n = 0; n < mbi_range_nr; n++) + kfree(mbi_ranges[n].bm); + kfree(mbi_ranges); + } + + return ret; +} diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index e5d101418390..5a67ec084588 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -1099,6 +1099,7 @@ static int __init gic_init_bases(void __iomem *dist_base, gic_data.domain = irq_domain_create_tree(handle, &gic_irq_domain_ops, &gic_data); + irq_domain_update_bus_token(gic_data.domain, DOMAIN_BUS_WIRED); gic_data.rdists.rdist = alloc_percpu(typeof(*gic_data.rdists.rdist)); gic_data.rdists.has_vlpis = true; gic_data.rdists.has_direct_lpi = true; @@ -1112,6 +1113,12 @@ static int __init gic_init_bases(void __iomem *dist_base, pr_info("Distributor has %sRange Selector support\n", gic_data.has_rss ? "" : "no "); + if (typer & GICD_TYPER_MBIS) { + err = mbi_init(handle, gic_data.domain); + if (err) + pr_err("Failed to initialize MBIs\n"); + } + set_handle_irq(gic_handle_irq); gic_update_vlpi_properties(); diff --git a/drivers/irqchip/irq-meson-gpio.c b/drivers/irqchip/irq-meson-gpio.c index a59bdbc0b9bb..7b531fd075b8 100644 --- a/drivers/irqchip/irq-meson-gpio.c +++ b/drivers/irqchip/irq-meson-gpio.c @@ -63,11 +63,16 @@ static const struct meson_gpio_irq_params gxl_params = { .nr_hwirq = 110, }; +static const struct meson_gpio_irq_params axg_params = { + .nr_hwirq = 100, +}; + static const struct of_device_id meson_irq_gpio_matches[] = { { .compatible = "amlogic,meson8-gpio-intc", .data = &meson8_params }, { .compatible = "amlogic,meson8b-gpio-intc", .data = &meson8b_params }, { .compatible = "amlogic,meson-gxbb-gpio-intc", .data = &gxbb_params }, { .compatible = "amlogic,meson-gxl-gpio-intc", .data = &gxl_params }, + { .compatible = "amlogic,meson-axg-gpio-intc", .data = &axg_params }, { } }; diff --git a/drivers/irqchip/irq-mvebu-gicp.c b/drivers/irqchip/irq-mvebu-gicp.c index 17a4a7b6cdbb..4e17f7081efc 100644 --- a/drivers/irqchip/irq-mvebu-gicp.c +++ b/drivers/irqchip/irq-mvebu-gicp.c @@ -19,8 +19,6 @@ #include <dt-bindings/interrupt-controller/arm-gic.h> -#include "irq-mvebu-gicp.h" - #define GICP_SETSPI_NSR_OFFSET 0x0 #define GICP_CLRSPI_NSR_OFFSET 0x8 @@ -55,34 +53,18 @@ static int gicp_idx_to_spi(struct mvebu_gicp *gicp, int idx) return -EINVAL; } -int mvebu_gicp_get_doorbells(struct device_node *dn, phys_addr_t *setspi, - phys_addr_t *clrspi) -{ - struct platform_device *pdev; - struct mvebu_gicp *gicp; - - pdev = of_find_device_by_node(dn); - if (!pdev) - return -ENODEV; - - gicp = platform_get_drvdata(pdev); - if (!gicp) - return -ENODEV; - - *setspi = gicp->res->start + GICP_SETSPI_NSR_OFFSET; - *clrspi = gicp->res->start + GICP_CLRSPI_NSR_OFFSET; - - return 0; -} - static void gicp_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) { struct mvebu_gicp *gicp = data->chip_data; phys_addr_t setspi = gicp->res->start + GICP_SETSPI_NSR_OFFSET; - - msg->data = data->hwirq; - msg->address_lo = lower_32_bits(setspi); - msg->address_hi = upper_32_bits(setspi); + phys_addr_t clrspi = gicp->res->start + GICP_CLRSPI_NSR_OFFSET; + + msg[0].data = data->hwirq; + msg[0].address_lo = lower_32_bits(setspi); + msg[0].address_hi = upper_32_bits(setspi); + msg[1].data = data->hwirq; + msg[1].address_lo = lower_32_bits(clrspi); + msg[1].address_hi = upper_32_bits(clrspi); } static struct irq_chip gicp_irq_chip = { @@ -170,13 +152,15 @@ static const struct irq_domain_ops gicp_domain_ops = { static struct irq_chip gicp_msi_irq_chip = { .name = "GICP", .irq_set_type = irq_chip_set_type_parent, + .flags = IRQCHIP_SUPPORTS_LEVEL_MSI, }; static struct msi_domain_ops gicp_msi_ops = { }; static struct msi_domain_info gicp_msi_domain_info = { - .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS), + .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | + MSI_FLAG_LEVEL_CAPABLE), .ops = &gicp_msi_ops, .chip = &gicp_msi_irq_chip, }; diff --git a/drivers/irqchip/irq-mvebu-gicp.h b/drivers/irqchip/irq-mvebu-gicp.h deleted file mode 100644 index eaa12fb72102..000000000000 --- a/drivers/irqchip/irq-mvebu-gicp.h +++ /dev/null @@ -1,12 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __MVEBU_GICP_H__ -#define __MVEBU_GICP_H__ - -#include <linux/types.h> - -struct device_node; - -int mvebu_gicp_get_doorbells(struct device_node *dn, phys_addr_t *setspi, - phys_addr_t *clrspi); - -#endif /* __MVEBU_GICP_H__ */ diff --git a/drivers/irqchip/irq-mvebu-icu.c b/drivers/irqchip/irq-mvebu-icu.c index e18c48d3a92e..13063339b416 100644 --- a/drivers/irqchip/irq-mvebu-icu.c +++ b/drivers/irqchip/irq-mvebu-icu.c @@ -21,8 +21,6 @@ #include <dt-bindings/interrupt-controller/mvebu-icu.h> -#include "irq-mvebu-gicp.h" - /* ICU registers */ #define ICU_SETSPI_NSR_AL 0x10 #define ICU_SETSPI_NSR_AH 0x14 @@ -43,6 +41,7 @@ struct mvebu_icu { void __iomem *base; struct irq_domain *domain; struct device *dev; + atomic_t initialized; }; struct mvebu_icu_irq_data { @@ -51,6 +50,18 @@ struct mvebu_icu_irq_data { unsigned int type; }; +static void mvebu_icu_init(struct mvebu_icu *icu, struct msi_msg *msg) +{ + if (atomic_cmpxchg(&icu->initialized, false, true)) + return; + + /* Set Clear/Set ICU SPI message address in AP */ + writel_relaxed(msg[0].address_hi, icu->base + ICU_SETSPI_NSR_AH); + writel_relaxed(msg[0].address_lo, icu->base + ICU_SETSPI_NSR_AL); + writel_relaxed(msg[1].address_hi, icu->base + ICU_CLRSPI_NSR_AH); + writel_relaxed(msg[1].address_lo, icu->base + ICU_CLRSPI_NSR_AL); +} + static void mvebu_icu_write_msg(struct msi_desc *desc, struct msi_msg *msg) { struct irq_data *d = irq_get_irq_data(desc->irq); @@ -59,6 +70,8 @@ static void mvebu_icu_write_msg(struct msi_desc *desc, struct msi_msg *msg) unsigned int icu_int; if (msg->address_lo || msg->address_hi) { + /* One off initialization */ + mvebu_icu_init(icu, msg); /* Configure the ICU with irq number & type */ icu_int = msg->data | ICU_INT_ENABLE; if (icu_irqd->type & IRQ_TYPE_EDGE_RISING) @@ -197,9 +210,7 @@ static int mvebu_icu_probe(struct platform_device *pdev) struct device_node *node = pdev->dev.of_node; struct device_node *gicp_dn; struct resource *res; - phys_addr_t setspi, clrspi; - u32 i, icu_int; - int ret; + int i; icu = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_icu), GFP_KERNEL); @@ -242,22 +253,12 @@ static int mvebu_icu_probe(struct platform_device *pdev) if (!gicp_dn) return -ENODEV; - ret = mvebu_gicp_get_doorbells(gicp_dn, &setspi, &clrspi); - if (ret) - return ret; - - /* Set Clear/Set ICU SPI message address in AP */ - writel_relaxed(upper_32_bits(setspi), icu->base + ICU_SETSPI_NSR_AH); - writel_relaxed(lower_32_bits(setspi), icu->base + ICU_SETSPI_NSR_AL); - writel_relaxed(upper_32_bits(clrspi), icu->base + ICU_CLRSPI_NSR_AH); - writel_relaxed(lower_32_bits(clrspi), icu->base + ICU_CLRSPI_NSR_AL); - /* * Clean all ICU interrupts with type SPI_NSR, required to * avoid unpredictable SPI assignments done by firmware. */ for (i = 0 ; i < ICU_MAX_IRQS ; i++) { - icu_int = readl(icu->base + ICU_INT_CFG(i)); + u32 icu_int = readl_relaxed(icu->base + ICU_INT_CFG(i)); if ((icu_int >> ICU_GROUP_SHIFT) == ICU_GRP_NSR) writel_relaxed(0x0, icu->base + ICU_INT_CFG(i)); } diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c index 36f0fbe36c35..5089c1e2838d 100644 --- a/drivers/irqchip/irq-stm32-exti.c +++ b/drivers/irqchip/irq-stm32-exti.c @@ -14,6 +14,9 @@ #include <linux/irqdomain.h> #include <linux/of_address.h> #include <linux/of_irq.h> +#include <linux/syscore_ops.h> + +#include <dt-bindings/interrupt-controller/arm-gic.h> #define IRQS_PER_BANK 32 @@ -23,29 +26,69 @@ struct stm32_exti_bank { u32 rtsr_ofst; u32 ftsr_ofst; u32 swier_ofst; - u32 pr_ofst; + u32 rpr_ofst; + u32 fpr_ofst; +}; + +#define UNDEF_REG ~0 + +struct stm32_desc_irq { + u32 exti; + u32 irq_parent; +}; + +struct stm32_exti_drv_data { + const struct stm32_exti_bank **exti_banks; + const struct stm32_desc_irq *desc_irqs; + u32 bank_nr; + u32 irq_nr; +}; + +struct stm32_exti_chip_data { + struct stm32_exti_host_data *host_data; + const struct stm32_exti_bank *reg_bank; + struct raw_spinlock rlock; + u32 wake_active; + u32 mask_cache; + u32 rtsr_cache; + u32 ftsr_cache; }; +struct stm32_exti_host_data { + void __iomem *base; + struct stm32_exti_chip_data *chips_data; + const struct stm32_exti_drv_data *drv_data; +}; + +static struct stm32_exti_host_data *stm32_host_data; + static const struct stm32_exti_bank stm32f4xx_exti_b1 = { .imr_ofst = 0x00, .emr_ofst = 0x04, .rtsr_ofst = 0x08, .ftsr_ofst = 0x0C, .swier_ofst = 0x10, - .pr_ofst = 0x14, + .rpr_ofst = 0x14, + .fpr_ofst = UNDEF_REG, }; static const struct stm32_exti_bank *stm32f4xx_exti_banks[] = { &stm32f4xx_exti_b1, }; +static const struct stm32_exti_drv_data stm32f4xx_drv_data = { + .exti_banks = stm32f4xx_exti_banks, + .bank_nr = ARRAY_SIZE(stm32f4xx_exti_banks), +}; + static const struct stm32_exti_bank stm32h7xx_exti_b1 = { .imr_ofst = 0x80, .emr_ofst = 0x84, .rtsr_ofst = 0x00, .ftsr_ofst = 0x04, .swier_ofst = 0x08, - .pr_ofst = 0x88, + .rpr_ofst = 0x88, + .fpr_ofst = UNDEF_REG, }; static const struct stm32_exti_bank stm32h7xx_exti_b2 = { @@ -54,7 +97,8 @@ static const struct stm32_exti_bank stm32h7xx_exti_b2 = { .rtsr_ofst = 0x20, .ftsr_ofst = 0x24, .swier_ofst = 0x28, - .pr_ofst = 0x98, + .rpr_ofst = 0x98, + .fpr_ofst = UNDEF_REG, }; static const struct stm32_exti_bank stm32h7xx_exti_b3 = { @@ -63,7 +107,8 @@ static const struct stm32_exti_bank stm32h7xx_exti_b3 = { .rtsr_ofst = 0x40, .ftsr_ofst = 0x44, .swier_ofst = 0x48, - .pr_ofst = 0xA8, + .rpr_ofst = 0xA8, + .fpr_ofst = UNDEF_REG, }; static const struct stm32_exti_bank *stm32h7xx_exti_banks[] = { @@ -72,18 +117,105 @@ static const struct stm32_exti_bank *stm32h7xx_exti_banks[] = { &stm32h7xx_exti_b3, }; -static unsigned long stm32_exti_pending(struct irq_chip_generic *gc) +static const struct stm32_exti_drv_data stm32h7xx_drv_data = { + .exti_banks = stm32h7xx_exti_banks, + .bank_nr = ARRAY_SIZE(stm32h7xx_exti_banks), +}; + +static const struct stm32_exti_bank stm32mp1_exti_b1 = { + .imr_ofst = 0x80, + .emr_ofst = 0x84, + .rtsr_ofst = 0x00, + .ftsr_ofst = 0x04, + .swier_ofst = 0x08, + .rpr_ofst = 0x0C, + .fpr_ofst = 0x10, +}; + +static const struct stm32_exti_bank stm32mp1_exti_b2 = { + .imr_ofst = 0x90, + .emr_ofst = 0x94, + .rtsr_ofst = 0x20, + .ftsr_ofst = 0x24, + .swier_ofst = 0x28, + .rpr_ofst = 0x2C, + .fpr_ofst = 0x30, +}; + +static const struct stm32_exti_bank stm32mp1_exti_b3 = { + .imr_ofst = 0xA0, + .emr_ofst = 0xA4, + .rtsr_ofst = 0x40, + .ftsr_ofst = 0x44, + .swier_ofst = 0x48, + .rpr_ofst = 0x4C, + .fpr_ofst = 0x50, +}; + +static const struct stm32_exti_bank *stm32mp1_exti_banks[] = { + &stm32mp1_exti_b1, + &stm32mp1_exti_b2, + &stm32mp1_exti_b3, +}; + +static const struct stm32_desc_irq stm32mp1_desc_irq[] = { + { .exti = 1, .irq_parent = 7 }, + { .exti = 2, .irq_parent = 8 }, + { .exti = 3, .irq_parent = 9 }, + { .exti = 4, .irq_parent = 10 }, + { .exti = 5, .irq_parent = 23 }, + { .exti = 6, .irq_parent = 64 }, + { .exti = 7, .irq_parent = 65 }, + { .exti = 8, .irq_parent = 66 }, + { .exti = 9, .irq_parent = 67 }, + { .exti = 10, .irq_parent = 40 }, + { .exti = 11, .irq_parent = 42 }, + { .exti = 12, .irq_parent = 76 }, + { .exti = 13, .irq_parent = 77 }, + { .exti = 14, .irq_parent = 121 }, + { .exti = 15, .irq_parent = 127 }, + { .exti = 16, .irq_parent = 1 }, + { .exti = 65, .irq_parent = 144 }, + { .exti = 68, .irq_parent = 143 }, + { .exti = 73, .irq_parent = 129 }, +}; + +static const struct stm32_exti_drv_data stm32mp1_drv_data = { + .exti_banks = stm32mp1_exti_banks, + .bank_nr = ARRAY_SIZE(stm32mp1_exti_banks), + .desc_irqs = stm32mp1_desc_irq, + .irq_nr = ARRAY_SIZE(stm32mp1_desc_irq), +}; + +static int stm32_exti_to_irq(const struct stm32_exti_drv_data *drv_data, + irq_hw_number_t hwirq) { - const struct stm32_exti_bank *stm32_bank = gc->private; + const struct stm32_desc_irq *desc_irq; + int i; - return irq_reg_readl(gc, stm32_bank->pr_ofst); + if (!drv_data->desc_irqs) + return -EINVAL; + + for (i = 0; i < drv_data->irq_nr; i++) { + desc_irq = &drv_data->desc_irqs[i]; + if (desc_irq->exti == hwirq) + return desc_irq->irq_parent; + } + + return -EINVAL; } -static void stm32_exti_irq_ack(struct irq_chip_generic *gc, u32 mask) +static unsigned long stm32_exti_pending(struct irq_chip_generic *gc) { - const struct stm32_exti_bank *stm32_bank = gc->private; + struct stm32_exti_chip_data *chip_data = gc->private; + const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; + unsigned long pending; + + pending = irq_reg_readl(gc, stm32_bank->rpr_ofst); + if (stm32_bank->fpr_ofst != UNDEF_REG) + pending |= irq_reg_readl(gc, stm32_bank->fpr_ofst); - irq_reg_writel(gc, mask, stm32_bank->pr_ofst); + return pending; } static void stm32_irq_handler(struct irq_desc *desc) @@ -92,7 +224,6 @@ static void stm32_irq_handler(struct irq_desc *desc) struct irq_chip *chip = irq_desc_get_chip(desc); unsigned int virq, nbanks = domain->gc->num_chips; struct irq_chip_generic *gc; - const struct stm32_exti_bank *stm32_bank; unsigned long pending; int n, i, irq_base = 0; @@ -100,13 +231,11 @@ static void stm32_irq_handler(struct irq_desc *desc) for (i = 0; i < nbanks; i++, irq_base += IRQS_PER_BANK) { gc = irq_get_domain_generic_chip(domain, irq_base); - stm32_bank = gc->private; while ((pending = stm32_exti_pending(gc))) { for_each_set_bit(n, &pending, IRQS_PER_BANK) { virq = irq_find_mapping(domain, irq_base + n); generic_handle_irq(virq); - stm32_exti_irq_ack(gc, BIT(n)); } } } @@ -114,36 +243,50 @@ static void stm32_irq_handler(struct irq_desc *desc) chained_irq_exit(chip, desc); } -static int stm32_irq_set_type(struct irq_data *data, unsigned int type) +static int stm32_exti_set_type(struct irq_data *d, + unsigned int type, u32 *rtsr, u32 *ftsr) { - struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); - const struct stm32_exti_bank *stm32_bank = gc->private; - int pin = data->hwirq % IRQS_PER_BANK; - u32 rtsr, ftsr; - - irq_gc_lock(gc); - - rtsr = irq_reg_readl(gc, stm32_bank->rtsr_ofst); - ftsr = irq_reg_readl(gc, stm32_bank->ftsr_ofst); + u32 mask = BIT(d->hwirq % IRQS_PER_BANK); switch (type) { case IRQ_TYPE_EDGE_RISING: - rtsr |= BIT(pin); - ftsr &= ~BIT(pin); + *rtsr |= mask; + *ftsr &= ~mask; break; case IRQ_TYPE_EDGE_FALLING: - rtsr &= ~BIT(pin); - ftsr |= BIT(pin); + *rtsr &= ~mask; + *ftsr |= mask; break; case IRQ_TYPE_EDGE_BOTH: - rtsr |= BIT(pin); - ftsr |= BIT(pin); + *rtsr |= mask; + *ftsr |= mask; break; default: - irq_gc_unlock(gc); return -EINVAL; } + return 0; +} + +static int stm32_irq_set_type(struct irq_data *d, unsigned int type) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct stm32_exti_chip_data *chip_data = gc->private; + const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; + u32 rtsr, ftsr; + int err; + + irq_gc_lock(gc); + + rtsr = irq_reg_readl(gc, stm32_bank->rtsr_ofst); + ftsr = irq_reg_readl(gc, stm32_bank->ftsr_ofst); + + err = stm32_exti_set_type(d, type, &rtsr, &ftsr); + if (err) { + irq_gc_unlock(gc); + return err; + } + irq_reg_writel(gc, rtsr, stm32_bank->rtsr_ofst); irq_reg_writel(gc, ftsr, stm32_bank->ftsr_ofst); @@ -152,40 +295,59 @@ static int stm32_irq_set_type(struct irq_data *data, unsigned int type) return 0; } -static int stm32_irq_set_wake(struct irq_data *data, unsigned int on) +static void stm32_chip_suspend(struct stm32_exti_chip_data *chip_data, + u32 wake_active) { - struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); - const struct stm32_exti_bank *stm32_bank = gc->private; - int pin = data->hwirq % IRQS_PER_BANK; - u32 imr; + const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; + void __iomem *base = chip_data->host_data->base; - irq_gc_lock(gc); + /* save rtsr, ftsr registers */ + chip_data->rtsr_cache = readl_relaxed(base + stm32_bank->rtsr_ofst); + chip_data->ftsr_cache = readl_relaxed(base + stm32_bank->ftsr_ofst); - imr = irq_reg_readl(gc, stm32_bank->imr_ofst); - if (on) - imr |= BIT(pin); - else - imr &= ~BIT(pin); - irq_reg_writel(gc, imr, stm32_bank->imr_ofst); + writel_relaxed(wake_active, base + stm32_bank->imr_ofst); +} + +static void stm32_chip_resume(struct stm32_exti_chip_data *chip_data, + u32 mask_cache) +{ + const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; + void __iomem *base = chip_data->host_data->base; + + /* restore rtsr, ftsr, registers */ + writel_relaxed(chip_data->rtsr_cache, base + stm32_bank->rtsr_ofst); + writel_relaxed(chip_data->ftsr_cache, base + stm32_bank->ftsr_ofst); + writel_relaxed(mask_cache, base + stm32_bank->imr_ofst); +} + +static void stm32_irq_suspend(struct irq_chip_generic *gc) +{ + struct stm32_exti_chip_data *chip_data = gc->private; + + irq_gc_lock(gc); + stm32_chip_suspend(chip_data, gc->wake_active); irq_gc_unlock(gc); +} - return 0; +static void stm32_irq_resume(struct irq_chip_generic *gc) +{ + struct stm32_exti_chip_data *chip_data = gc->private; + + irq_gc_lock(gc); + stm32_chip_resume(chip_data, gc->mask_cache); + irq_gc_unlock(gc); } static int stm32_exti_alloc(struct irq_domain *d, unsigned int virq, unsigned int nr_irqs, void *data) { - struct irq_chip_generic *gc; struct irq_fwspec *fwspec = data; irq_hw_number_t hwirq; hwirq = fwspec->param[0]; - gc = irq_get_domain_generic_chip(d, hwirq); irq_map_generic_chip(d, virq, hwirq); - irq_domain_set_info(d, virq, hwirq, &gc->chip_types->chip, gc, - handle_simple_irq, NULL, NULL); return 0; } @@ -198,30 +360,318 @@ static void stm32_exti_free(struct irq_domain *d, unsigned int virq, irq_domain_reset_irq_data(data); } -struct irq_domain_ops irq_exti_domain_ops = { +static const struct irq_domain_ops irq_exti_domain_ops = { .map = irq_map_generic_chip, - .xlate = irq_domain_xlate_onetwocell, .alloc = stm32_exti_alloc, .free = stm32_exti_free, }; -static int -__init stm32_exti_init(const struct stm32_exti_bank **stm32_exti_banks, - int bank_nr, struct device_node *node) +static void stm32_irq_ack(struct irq_data *d) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct stm32_exti_chip_data *chip_data = gc->private; + const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; + + irq_gc_lock(gc); + + irq_reg_writel(gc, d->mask, stm32_bank->rpr_ofst); + if (stm32_bank->fpr_ofst != UNDEF_REG) + irq_reg_writel(gc, d->mask, stm32_bank->fpr_ofst); + + irq_gc_unlock(gc); +} + +static inline u32 stm32_exti_set_bit(struct irq_data *d, u32 reg) { + struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); + void __iomem *base = chip_data->host_data->base; + u32 val; + + val = readl_relaxed(base + reg); + val |= BIT(d->hwirq % IRQS_PER_BANK); + writel_relaxed(val, base + reg); + + return val; +} + +static inline u32 stm32_exti_clr_bit(struct irq_data *d, u32 reg) +{ + struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); + void __iomem *base = chip_data->host_data->base; + u32 val; + + val = readl_relaxed(base + reg); + val &= ~BIT(d->hwirq % IRQS_PER_BANK); + writel_relaxed(val, base + reg); + + return val; +} + +static void stm32_exti_h_eoi(struct irq_data *d) +{ + struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); + const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; + + raw_spin_lock(&chip_data->rlock); + + stm32_exti_set_bit(d, stm32_bank->rpr_ofst); + if (stm32_bank->fpr_ofst != UNDEF_REG) + stm32_exti_set_bit(d, stm32_bank->fpr_ofst); + + raw_spin_unlock(&chip_data->rlock); + + if (d->parent_data->chip) + irq_chip_eoi_parent(d); +} + +static void stm32_exti_h_mask(struct irq_data *d) +{ + struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); + const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; + + raw_spin_lock(&chip_data->rlock); + chip_data->mask_cache = stm32_exti_clr_bit(d, stm32_bank->imr_ofst); + raw_spin_unlock(&chip_data->rlock); + + if (d->parent_data->chip) + irq_chip_mask_parent(d); +} + +static void stm32_exti_h_unmask(struct irq_data *d) +{ + struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); + const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; + + raw_spin_lock(&chip_data->rlock); + chip_data->mask_cache = stm32_exti_set_bit(d, stm32_bank->imr_ofst); + raw_spin_unlock(&chip_data->rlock); + + if (d->parent_data->chip) + irq_chip_unmask_parent(d); +} + +static int stm32_exti_h_set_type(struct irq_data *d, unsigned int type) +{ + struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); + const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; + void __iomem *base = chip_data->host_data->base; + u32 rtsr, ftsr; + int err; + + raw_spin_lock(&chip_data->rlock); + rtsr = readl_relaxed(base + stm32_bank->rtsr_ofst); + ftsr = readl_relaxed(base + stm32_bank->ftsr_ofst); + + err = stm32_exti_set_type(d, type, &rtsr, &ftsr); + if (err) { + raw_spin_unlock(&chip_data->rlock); + return err; + } + + writel_relaxed(rtsr, base + stm32_bank->rtsr_ofst); + writel_relaxed(ftsr, base + stm32_bank->ftsr_ofst); + raw_spin_unlock(&chip_data->rlock); + + return 0; +} + +static int stm32_exti_h_set_wake(struct irq_data *d, unsigned int on) +{ + struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); + u32 mask = BIT(d->hwirq % IRQS_PER_BANK); + + raw_spin_lock(&chip_data->rlock); + + if (on) + chip_data->wake_active |= mask; + else + chip_data->wake_active &= ~mask; + + raw_spin_unlock(&chip_data->rlock); + + return 0; +} + +static int stm32_exti_h_set_affinity(struct irq_data *d, + const struct cpumask *dest, bool force) +{ + if (d->parent_data->chip) + return irq_chip_set_affinity_parent(d, dest, force); + + return -EINVAL; +} + +#ifdef CONFIG_PM +static int stm32_exti_h_suspend(void) +{ + struct stm32_exti_chip_data *chip_data; + int i; + + for (i = 0; i < stm32_host_data->drv_data->bank_nr; i++) { + chip_data = &stm32_host_data->chips_data[i]; + raw_spin_lock(&chip_data->rlock); + stm32_chip_suspend(chip_data, chip_data->wake_active); + raw_spin_unlock(&chip_data->rlock); + } + + return 0; +} + +static void stm32_exti_h_resume(void) +{ + struct stm32_exti_chip_data *chip_data; + int i; + + for (i = 0; i < stm32_host_data->drv_data->bank_nr; i++) { + chip_data = &stm32_host_data->chips_data[i]; + raw_spin_lock(&chip_data->rlock); + stm32_chip_resume(chip_data, chip_data->mask_cache); + raw_spin_unlock(&chip_data->rlock); + } +} + +static struct syscore_ops stm32_exti_h_syscore_ops = { + .suspend = stm32_exti_h_suspend, + .resume = stm32_exti_h_resume, +}; + +static void stm32_exti_h_syscore_init(void) +{ + register_syscore_ops(&stm32_exti_h_syscore_ops); +} +#else +static inline void stm32_exti_h_syscore_init(void) {} +#endif + +static struct irq_chip stm32_exti_h_chip = { + .name = "stm32-exti-h", + .irq_eoi = stm32_exti_h_eoi, + .irq_mask = stm32_exti_h_mask, + .irq_unmask = stm32_exti_h_unmask, + .irq_retrigger = irq_chip_retrigger_hierarchy, + .irq_set_type = stm32_exti_h_set_type, + .irq_set_wake = stm32_exti_h_set_wake, + .flags = IRQCHIP_MASK_ON_SUSPEND, +#ifdef CONFIG_SMP + .irq_set_affinity = stm32_exti_h_set_affinity, +#endif +}; + +static int stm32_exti_h_domain_alloc(struct irq_domain *dm, + unsigned int virq, + unsigned int nr_irqs, void *data) +{ + struct stm32_exti_host_data *host_data = dm->host_data; + struct stm32_exti_chip_data *chip_data; + struct irq_fwspec *fwspec = data; + struct irq_fwspec p_fwspec; + irq_hw_number_t hwirq; + int p_irq, bank; + + hwirq = fwspec->param[0]; + bank = hwirq / IRQS_PER_BANK; + chip_data = &host_data->chips_data[bank]; + + irq_domain_set_hwirq_and_chip(dm, virq, hwirq, + &stm32_exti_h_chip, chip_data); + + p_irq = stm32_exti_to_irq(host_data->drv_data, hwirq); + if (p_irq >= 0) { + p_fwspec.fwnode = dm->parent->fwnode; + p_fwspec.param_count = 3; + p_fwspec.param[0] = GIC_SPI; + p_fwspec.param[1] = p_irq; + p_fwspec.param[2] = IRQ_TYPE_LEVEL_HIGH; + + return irq_domain_alloc_irqs_parent(dm, virq, 1, &p_fwspec); + } + + return 0; +} + +static struct +stm32_exti_host_data *stm32_exti_host_init(const struct stm32_exti_drv_data *dd, + struct device_node *node) +{ + struct stm32_exti_host_data *host_data; + + host_data = kzalloc(sizeof(*host_data), GFP_KERNEL); + if (!host_data) + return NULL; + + host_data->drv_data = dd; + host_data->chips_data = kcalloc(dd->bank_nr, + sizeof(struct stm32_exti_chip_data), + GFP_KERNEL); + if (!host_data->chips_data) + return NULL; + + host_data->base = of_iomap(node, 0); + if (!host_data->base) { + pr_err("%pOF: Unable to map registers\n", node); + return NULL; + } + + stm32_host_data = host_data; + + return host_data; +} + +static struct +stm32_exti_chip_data *stm32_exti_chip_init(struct stm32_exti_host_data *h_data, + u32 bank_idx, + struct device_node *node) +{ + const struct stm32_exti_bank *stm32_bank; + struct stm32_exti_chip_data *chip_data; + void __iomem *base = h_data->base; + u32 irqs_mask; + + stm32_bank = h_data->drv_data->exti_banks[bank_idx]; + chip_data = &h_data->chips_data[bank_idx]; + chip_data->host_data = h_data; + chip_data->reg_bank = stm32_bank; + + raw_spin_lock_init(&chip_data->rlock); + + /* Determine number of irqs supported */ + writel_relaxed(~0UL, base + stm32_bank->rtsr_ofst); + irqs_mask = readl_relaxed(base + stm32_bank->rtsr_ofst); + + /* + * This IP has no reset, so after hot reboot we should + * clear registers to avoid residue + */ + writel_relaxed(0, base + stm32_bank->imr_ofst); + writel_relaxed(0, base + stm32_bank->emr_ofst); + writel_relaxed(0, base + stm32_bank->rtsr_ofst); + writel_relaxed(0, base + stm32_bank->ftsr_ofst); + writel_relaxed(~0UL, base + stm32_bank->rpr_ofst); + if (stm32_bank->fpr_ofst != UNDEF_REG) + writel_relaxed(~0UL, base + stm32_bank->fpr_ofst); + + pr_info("%s: bank%d, External IRQs available:%#x\n", + node->full_name, bank_idx, irqs_mask); + + return chip_data; +} + +static int __init stm32_exti_init(const struct stm32_exti_drv_data *drv_data, + struct device_node *node) +{ + struct stm32_exti_host_data *host_data; unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; - int nr_irqs, nr_exti, ret, i; + int nr_irqs, ret, i; struct irq_chip_generic *gc; struct irq_domain *domain; - void *base; - base = of_iomap(node, 0); - if (!base) { - pr_err("%pOF: Unable to map registers\n", node); - return -ENOMEM; + host_data = stm32_exti_host_init(drv_data, node); + if (!host_data) { + ret = -ENOMEM; + goto out_free_mem; } - domain = irq_domain_add_linear(node, bank_nr * IRQS_PER_BANK, + domain = irq_domain_add_linear(node, drv_data->bank_nr * IRQS_PER_BANK, &irq_exti_domain_ops, NULL); if (!domain) { pr_err("%s: Could not register interrupt domain.\n", @@ -234,44 +684,32 @@ __init stm32_exti_init(const struct stm32_exti_bank **stm32_exti_banks, handle_edge_irq, clr, 0, 0); if (ret) { pr_err("%pOF: Could not allocate generic interrupt chip.\n", - node); + node); goto out_free_domain; } - for (i = 0; i < bank_nr; i++) { - const struct stm32_exti_bank *stm32_bank = stm32_exti_banks[i]; - u32 irqs_mask; + for (i = 0; i < drv_data->bank_nr; i++) { + const struct stm32_exti_bank *stm32_bank; + struct stm32_exti_chip_data *chip_data; + + stm32_bank = drv_data->exti_banks[i]; + chip_data = stm32_exti_chip_init(host_data, i, node); gc = irq_get_domain_generic_chip(domain, i * IRQS_PER_BANK); - gc->reg_base = base; + gc->reg_base = host_data->base; gc->chip_types->type = IRQ_TYPE_EDGE_BOTH; - gc->chip_types->chip.irq_ack = irq_gc_ack_set_bit; + gc->chip_types->chip.irq_ack = stm32_irq_ack; gc->chip_types->chip.irq_mask = irq_gc_mask_clr_bit; gc->chip_types->chip.irq_unmask = irq_gc_mask_set_bit; gc->chip_types->chip.irq_set_type = stm32_irq_set_type; - gc->chip_types->chip.irq_set_wake = stm32_irq_set_wake; - gc->chip_types->regs.ack = stm32_bank->pr_ofst; + gc->chip_types->chip.irq_set_wake = irq_gc_set_wake; + gc->suspend = stm32_irq_suspend; + gc->resume = stm32_irq_resume; + gc->wake_enabled = IRQ_MSK(IRQS_PER_BANK); + gc->chip_types->regs.mask = stm32_bank->imr_ofst; - gc->private = (void *)stm32_bank; - - /* Determine number of irqs supported */ - writel_relaxed(~0UL, base + stm32_bank->rtsr_ofst); - irqs_mask = readl_relaxed(base + stm32_bank->rtsr_ofst); - nr_exti = fls(readl_relaxed(base + stm32_bank->rtsr_ofst)); - - /* - * This IP has no reset, so after hot reboot we should - * clear registers to avoid residue - */ - writel_relaxed(0, base + stm32_bank->imr_ofst); - writel_relaxed(0, base + stm32_bank->emr_ofst); - writel_relaxed(0, base + stm32_bank->rtsr_ofst); - writel_relaxed(0, base + stm32_bank->ftsr_ofst); - writel_relaxed(~0UL, base + stm32_bank->pr_ofst); - - pr_info("%s: bank%d, External IRQs available:%#x\n", - node->full_name, i, irqs_mask); + gc->private = (void *)chip_data; } nr_irqs = of_irq_count(node); @@ -287,15 +725,69 @@ __init stm32_exti_init(const struct stm32_exti_bank **stm32_exti_banks, out_free_domain: irq_domain_remove(domain); out_unmap: - iounmap(base); + iounmap(host_data->base); +out_free_mem: + kfree(host_data->chips_data); + kfree(host_data); + return ret; +} + +static const struct irq_domain_ops stm32_exti_h_domain_ops = { + .alloc = stm32_exti_h_domain_alloc, + .free = irq_domain_free_irqs_common, +}; + +static int +__init stm32_exti_hierarchy_init(const struct stm32_exti_drv_data *drv_data, + struct device_node *node, + struct device_node *parent) +{ + struct irq_domain *parent_domain, *domain; + struct stm32_exti_host_data *host_data; + int ret, i; + + parent_domain = irq_find_host(parent); + if (!parent_domain) { + pr_err("interrupt-parent not found\n"); + return -EINVAL; + } + + host_data = stm32_exti_host_init(drv_data, node); + if (!host_data) { + ret = -ENOMEM; + goto out_free_mem; + } + + for (i = 0; i < drv_data->bank_nr; i++) + stm32_exti_chip_init(host_data, i, node); + + domain = irq_domain_add_hierarchy(parent_domain, 0, + drv_data->bank_nr * IRQS_PER_BANK, + node, &stm32_exti_h_domain_ops, + host_data); + + if (!domain) { + pr_err("%s: Could not register exti domain.\n", node->name); + ret = -ENOMEM; + goto out_unmap; + } + + stm32_exti_h_syscore_init(); + + return 0; + +out_unmap: + iounmap(host_data->base); +out_free_mem: + kfree(host_data->chips_data); + kfree(host_data); return ret; } static int __init stm32f4_exti_of_init(struct device_node *np, struct device_node *parent) { - return stm32_exti_init(stm32f4xx_exti_banks, - ARRAY_SIZE(stm32f4xx_exti_banks), np); + return stm32_exti_init(&stm32f4xx_drv_data, np); } IRQCHIP_DECLARE(stm32f4_exti, "st,stm32-exti", stm32f4_exti_of_init); @@ -303,8 +795,15 @@ IRQCHIP_DECLARE(stm32f4_exti, "st,stm32-exti", stm32f4_exti_of_init); static int __init stm32h7_exti_of_init(struct device_node *np, struct device_node *parent) { - return stm32_exti_init(stm32h7xx_exti_banks, - ARRAY_SIZE(stm32h7xx_exti_banks), np); + return stm32_exti_init(&stm32h7xx_drv_data, np); } IRQCHIP_DECLARE(stm32h7_exti, "st,stm32h7-exti", stm32h7_exti_of_init); + +static int __init stm32mp1_exti_of_init(struct device_node *np, + struct device_node *parent) +{ + return stm32_exti_hierarchy_init(&stm32mp1_drv_data, np, parent); +} + +IRQCHIP_DECLARE(stm32mp1_exti, "st,stm32mp1-exti", stm32mp1_exti_of_init); diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c index 1f8f489b4167..98f90aadd141 100644 --- a/drivers/isdn/mISDN/socket.c +++ b/drivers/isdn/mISDN/socket.c @@ -588,7 +588,7 @@ static const struct proto_ops data_sock_ops = { .getname = data_sock_getname, .sendmsg = mISDN_sock_sendmsg, .recvmsg = mISDN_sock_recvmsg, - .poll = datagram_poll, + .poll_mask = datagram_poll_mask, .listen = sock_no_listen, .shutdown = sock_no_shutdown, .setsockopt = data_sock_setsockopt, @@ -745,7 +745,6 @@ static const struct proto_ops base_sock_ops = { .getname = sock_no_getname, .sendmsg = sock_no_sendmsg, .recvmsg = sock_no_recvmsg, - .poll = sock_no_poll, .listen = sock_no_listen, .shutdown = sock_no_shutdown, .setsockopt = sock_no_setsockopt, diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c index d7f54e492aa6..c63e331738c1 100644 --- a/drivers/mfd/mc13xxx-core.c +++ b/drivers/mfd/mc13xxx-core.c @@ -279,8 +279,21 @@ int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode, adc0 = MC13XXX_ADC0_ADINC1 | MC13XXX_ADC0_ADINC2; adc1 = MC13XXX_ADC1_ADEN | MC13XXX_ADC1_ADTRIGIGN | MC13XXX_ADC1_ASC; - if (channel > 7) + /* + * Channels mapped through ADIN7: + * 7 - General purpose ADIN7 + * 16 - UID + * 17 - Die temperature + */ + if (channel > 7 && channel < 16) { adc1 |= MC13XXX_ADC1_ADSEL; + } else if (channel == 16) { + adc0 |= MC13XXX_ADC0_ADIN7SEL_UID; + channel = 7; + } else if (channel == 17) { + adc0 |= MC13XXX_ADC0_ADIN7SEL_DIE; + channel = 7; + } switch (mode) { case MC13XXX_ADC_MODE_TS: diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig index 6def5445e03e..57b02c4b3f63 100644 --- a/drivers/mtd/devices/Kconfig +++ b/drivers/mtd/devices/Kconfig @@ -81,6 +81,7 @@ config MTD_DATAFLASH_OTP config MTD_M25P80 tristate "Support most SPI Flash chips (AT26DF, M25P, W25X, ...)" depends on SPI_MASTER && MTD_SPI_NOR + select SPI_MEM help This enables access to most modern SPI flash chips, used for program and data storage. Series supported include Atmel AT26DF, diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index a4e18f6aaa33..e84563d2067f 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -24,12 +24,13 @@ #include <linux/mtd/partitions.h> #include <linux/spi/spi.h> +#include <linux/spi/spi-mem.h> #include <linux/spi/flash.h> #include <linux/mtd/spi-nor.h> #define MAX_CMD_SIZE 6 struct m25p { - struct spi_device *spi; + struct spi_mem *spimem; struct spi_nor spi_nor; u8 command[MAX_CMD_SIZE]; }; @@ -37,97 +38,68 @@ struct m25p { static int m25p80_read_reg(struct spi_nor *nor, u8 code, u8 *val, int len) { struct m25p *flash = nor->priv; - struct spi_device *spi = flash->spi; + struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(code, 1), + SPI_MEM_OP_NO_ADDR, + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_IN(len, val, 1)); int ret; - ret = spi_write_then_read(spi, &code, 1, val, len); + ret = spi_mem_exec_op(flash->spimem, &op); if (ret < 0) - dev_err(&spi->dev, "error %d reading %x\n", ret, code); + dev_err(&flash->spimem->spi->dev, "error %d reading %x\n", ret, + code); return ret; } -static void m25p_addr2cmd(struct spi_nor *nor, unsigned int addr, u8 *cmd) -{ - /* opcode is in cmd[0] */ - cmd[1] = addr >> (nor->addr_width * 8 - 8); - cmd[2] = addr >> (nor->addr_width * 8 - 16); - cmd[3] = addr >> (nor->addr_width * 8 - 24); - cmd[4] = addr >> (nor->addr_width * 8 - 32); -} - -static int m25p_cmdsz(struct spi_nor *nor) -{ - return 1 + nor->addr_width; -} - static int m25p80_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len) { struct m25p *flash = nor->priv; - struct spi_device *spi = flash->spi; - - flash->command[0] = opcode; - if (buf) - memcpy(&flash->command[1], buf, len); + struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(opcode, 1), + SPI_MEM_OP_NO_ADDR, + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_OUT(len, buf, 1)); - return spi_write(spi, flash->command, len + 1); + return spi_mem_exec_op(flash->spimem, &op); } static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len, const u_char *buf) { struct m25p *flash = nor->priv; - struct spi_device *spi = flash->spi; - unsigned int inst_nbits, addr_nbits, data_nbits, data_idx; - struct spi_transfer t[3] = {}; - struct spi_message m; - int cmd_sz = m25p_cmdsz(nor); - ssize_t ret; + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 1), + SPI_MEM_OP_ADDR(nor->addr_width, to, 1), + SPI_MEM_OP_DUMMY(0, 1), + SPI_MEM_OP_DATA_OUT(len, buf, 1)); + size_t remaining = len; + int ret; /* get transfer protocols. */ - inst_nbits = spi_nor_get_protocol_inst_nbits(nor->write_proto); - addr_nbits = spi_nor_get_protocol_addr_nbits(nor->write_proto); - data_nbits = spi_nor_get_protocol_data_nbits(nor->write_proto); - - spi_message_init(&m); + op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->write_proto); + op.addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->write_proto); + op.dummy.buswidth = op.addr.buswidth; + op.data.buswidth = spi_nor_get_protocol_data_nbits(nor->write_proto); if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second) - cmd_sz = 1; - - flash->command[0] = nor->program_opcode; - m25p_addr2cmd(nor, to, flash->command); + op.addr.nbytes = 0; - t[0].tx_buf = flash->command; - t[0].tx_nbits = inst_nbits; - t[0].len = cmd_sz; - spi_message_add_tail(&t[0], &m); - - /* split the op code and address bytes into two transfers if needed. */ - data_idx = 1; - if (addr_nbits != inst_nbits) { - t[0].len = 1; + while (remaining) { + op.data.nbytes = remaining < UINT_MAX ? remaining : UINT_MAX; + ret = spi_mem_adjust_op_size(flash->spimem, &op); + if (ret) + return ret; - t[1].tx_buf = &flash->command[1]; - t[1].tx_nbits = addr_nbits; - t[1].len = cmd_sz - 1; - spi_message_add_tail(&t[1], &m); + ret = spi_mem_exec_op(flash->spimem, &op); + if (ret) + return ret; - data_idx = 2; + op.addr.val += op.data.nbytes; + remaining -= op.data.nbytes; + op.data.buf.out += op.data.nbytes; } - t[data_idx].tx_buf = buf; - t[data_idx].tx_nbits = data_nbits; - t[data_idx].len = len; - spi_message_add_tail(&t[data_idx], &m); - - ret = spi_sync(spi, &m); - if (ret) - return ret; - - ret = m.actual_length - cmd_sz; - if (ret < 0) - return -EIO; - return ret; + return len; } /* @@ -138,92 +110,39 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len, u_char *buf) { struct m25p *flash = nor->priv; - struct spi_device *spi = flash->spi; - unsigned int inst_nbits, addr_nbits, data_nbits, data_idx; - struct spi_transfer t[3]; - struct spi_message m; - unsigned int dummy = nor->read_dummy; - ssize_t ret; - int cmd_sz; + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 1), + SPI_MEM_OP_ADDR(nor->addr_width, from, 1), + SPI_MEM_OP_DUMMY(nor->read_dummy, 1), + SPI_MEM_OP_DATA_IN(len, buf, 1)); + size_t remaining = len; + int ret; /* get transfer protocols. */ - inst_nbits = spi_nor_get_protocol_inst_nbits(nor->read_proto); - addr_nbits = spi_nor_get_protocol_addr_nbits(nor->read_proto); - data_nbits = spi_nor_get_protocol_data_nbits(nor->read_proto); + op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->read_proto); + op.addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->read_proto); + op.dummy.buswidth = op.addr.buswidth; + op.data.buswidth = spi_nor_get_protocol_data_nbits(nor->read_proto); /* convert the dummy cycles to the number of bytes */ - dummy = (dummy * addr_nbits) / 8; - - if (spi_flash_read_supported(spi)) { - struct spi_flash_read_message msg; - - memset(&msg, 0, sizeof(msg)); + op.dummy.nbytes = (nor->read_dummy * op.dummy.buswidth) / 8; - msg.buf = buf; - msg.from = from; - msg.len = len; - msg.read_opcode = nor->read_opcode; - msg.addr_width = nor->addr_width; - msg.dummy_bytes = dummy; - msg.opcode_nbits = inst_nbits; - msg.addr_nbits = addr_nbits; - msg.data_nbits = data_nbits; - - ret = spi_flash_read(spi, &msg); - if (ret < 0) + while (remaining) { + op.data.nbytes = remaining < UINT_MAX ? remaining : UINT_MAX; + ret = spi_mem_adjust_op_size(flash->spimem, &op); + if (ret) return ret; - return msg.retlen; - } - spi_message_init(&m); - memset(t, 0, (sizeof t)); - - flash->command[0] = nor->read_opcode; - m25p_addr2cmd(nor, from, flash->command); - - t[0].tx_buf = flash->command; - t[0].tx_nbits = inst_nbits; - t[0].len = m25p_cmdsz(nor) + dummy; - spi_message_add_tail(&t[0], &m); - - /* - * Set all dummy/mode cycle bits to avoid sending some manufacturer - * specific pattern, which might make the memory enter its Continuous - * Read mode by mistake. - * Based on the different mode cycle bit patterns listed and described - * in the JESD216B specification, the 0xff value works for all memories - * and all manufacturers. - */ - cmd_sz = t[0].len; - memset(flash->command + cmd_sz - dummy, 0xff, dummy); - - /* split the op code and address bytes into two transfers if needed. */ - data_idx = 1; - if (addr_nbits != inst_nbits) { - t[0].len = 1; - - t[1].tx_buf = &flash->command[1]; - t[1].tx_nbits = addr_nbits; - t[1].len = cmd_sz - 1; - spi_message_add_tail(&t[1], &m); + ret = spi_mem_exec_op(flash->spimem, &op); + if (ret) + return ret; - data_idx = 2; + op.addr.val += op.data.nbytes; + remaining -= op.data.nbytes; + op.data.buf.in += op.data.nbytes; } - t[data_idx].rx_buf = buf; - t[data_idx].rx_nbits = data_nbits; - t[data_idx].len = min3(len, spi_max_transfer_size(spi), - spi_max_message_size(spi) - cmd_sz); - spi_message_add_tail(&t[data_idx], &m); - - ret = spi_sync(spi, &m); - if (ret) - return ret; - - ret = m.actual_length - cmd_sz; - if (ret < 0) - return -EIO; - return ret; + return len; } /* @@ -231,8 +150,9 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len, * matches what the READ command supports, at least until this driver * understands FAST_READ (for clocks over 25 MHz). */ -static int m25p_probe(struct spi_device *spi) +static int m25p_probe(struct spi_mem *spimem) { + struct spi_device *spi = spimem->spi; struct flash_platform_data *data; struct m25p *flash; struct spi_nor *nor; @@ -244,9 +164,9 @@ static int m25p_probe(struct spi_device *spi) char *flash_name; int ret; - data = dev_get_platdata(&spi->dev); + data = dev_get_platdata(&spimem->spi->dev); - flash = devm_kzalloc(&spi->dev, sizeof(*flash), GFP_KERNEL); + flash = devm_kzalloc(&spimem->spi->dev, sizeof(*flash), GFP_KERNEL); if (!flash) return -ENOMEM; @@ -258,12 +178,12 @@ static int m25p_probe(struct spi_device *spi) nor->write_reg = m25p80_write_reg; nor->read_reg = m25p80_read_reg; - nor->dev = &spi->dev; + nor->dev = &spimem->spi->dev; spi_nor_set_flash_node(nor, spi->dev.of_node); nor->priv = flash; - spi_set_drvdata(spi, flash); - flash->spi = spi; + spi_mem_set_drvdata(spimem, flash); + flash->spimem = spimem; if (spi->mode & SPI_RX_QUAD) { hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4; @@ -303,9 +223,9 @@ static int m25p_probe(struct spi_device *spi) } -static int m25p_remove(struct spi_device *spi) +static int m25p_remove(struct spi_mem *spimem) { - struct m25p *flash = spi_get_drvdata(spi); + struct m25p *flash = spi_mem_get_drvdata(spimem); spi_nor_restore(&flash->spi_nor); @@ -313,9 +233,9 @@ static int m25p_remove(struct spi_device *spi) return mtd_device_unregister(&flash->spi_nor.mtd); } -static void m25p_shutdown(struct spi_device *spi) +static void m25p_shutdown(struct spi_mem *spimem) { - struct m25p *flash = spi_get_drvdata(spi); + struct m25p *flash = spi_mem_get_drvdata(spimem); spi_nor_restore(&flash->spi_nor); } @@ -386,12 +306,14 @@ static const struct of_device_id m25p_of_table[] = { }; MODULE_DEVICE_TABLE(of, m25p_of_table); -static struct spi_driver m25p80_driver = { - .driver = { - .name = "m25p80", - .of_match_table = m25p_of_table, +static struct spi_mem_driver m25p80_driver = { + .spidrv = { + .driver = { + .name = "m25p80", + .of_match_table = m25p_of_table, + }, + .id_table = m25p_ids, }, - .id_table = m25p_ids, .probe = m25p_probe, .remove = m25p_remove, .shutdown = m25p_shutdown, @@ -402,7 +324,7 @@ static struct spi_driver m25p80_driver = { */ }; -module_spi_driver(m25p80_driver); +module_spi_mem_driver(m25p80_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mike Lavender"); diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index a4ebd8715494..661828e8fdcf 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -1289,9 +1289,8 @@ static int efx_init_io(struct efx_nic *efx) pci_set_master(pci_dev); - /* Set the PCI DMA mask. Try all possibilities from our - * genuine mask down to 32 bits, because some architectures - * (e.g. x86_64 with iommu_sac_force set) will allow 40 bit + /* Set the PCI DMA mask. Try all possibilities from our genuine mask + * down to 32 bits, because some architectures will allow 40 bit * masks event though they reject 46 bit masks. */ while (dma_mask > 0x7fffffffUL) { diff --git a/drivers/net/ethernet/sfc/falcon/efx.c b/drivers/net/ethernet/sfc/falcon/efx.c index 3d6c91e96589..dd5530a4f8c8 100644 --- a/drivers/net/ethernet/sfc/falcon/efx.c +++ b/drivers/net/ethernet/sfc/falcon/efx.c @@ -1242,9 +1242,8 @@ static int ef4_init_io(struct ef4_nic *efx) pci_set_master(pci_dev); - /* Set the PCI DMA mask. Try all possibilities from our - * genuine mask down to 32 bits, because some architectures - * (e.g. x86_64 with iommu_sac_force set) will allow 40 bit + /* Set the PCI DMA mask. Try all possibilities from our genuine mask + * down to 32 bits, because some architectures will allow 40 bit * masks event though they reject 46 bit masks. */ while (dma_mask > 0x7fffffffUL) { diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c index ce61231e96ea..de51e8f70f44 100644 --- a/drivers/net/ppp/pppoe.c +++ b/drivers/net/ppp/pppoe.c @@ -1107,7 +1107,7 @@ static const struct proto_ops pppoe_ops = { .socketpair = sock_no_socketpair, .accept = sock_no_accept, .getname = pppoe_getname, - .poll = datagram_poll, + .poll_mask = datagram_poll_mask, .listen = sock_no_listen, .shutdown = sock_no_shutdown, .setsockopt = sock_no_setsockopt, diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c index c4267ecefd85..157b67c1bf8e 100644 --- a/drivers/net/ppp/pptp.c +++ b/drivers/net/ppp/pptp.c @@ -624,7 +624,6 @@ static const struct proto_ops pptp_ops = { .socketpair = sock_no_socketpair, .accept = sock_no_accept, .getname = pptp_getname, - .poll = sock_no_poll, .listen = sock_no_listen, .shutdown = sock_no_shutdown, .setsockopt = sock_no_setsockopt, diff --git a/drivers/nvdimm/claim.c b/drivers/nvdimm/claim.c index 30852270484f..2e96b34bc936 100644 --- a/drivers/nvdimm/claim.c +++ b/drivers/nvdimm/claim.c @@ -276,7 +276,8 @@ static int nsio_rw_bytes(struct nd_namespace_common *ndns, if (rw == READ) { if (unlikely(is_bad_pmem(&nsio->bb, sector, sz_align))) return -EIO; - return memcpy_mcsafe(buf, nsio->addr + offset, size); + if (memcpy_mcsafe(buf, nsio->addr + offset, size) != 0) + return -EIO; } if (unlikely(is_bad_pmem(&nsio->bb, sector, sz_align))) { diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c index 9d714926ecf5..e023d6aa22b5 100644 --- a/drivers/nvdimm/pmem.c +++ b/drivers/nvdimm/pmem.c @@ -101,15 +101,15 @@ static blk_status_t read_pmem(struct page *page, unsigned int off, void *pmem_addr, unsigned int len) { unsigned int chunk; - int rc; + unsigned long rem; void *mem; while (len) { mem = kmap_atomic(page); chunk = min_t(unsigned int, len, PAGE_SIZE); - rc = memcpy_mcsafe(mem + off, pmem_addr, chunk); + rem = memcpy_mcsafe(mem + off, pmem_addr, chunk); kunmap_atomic(mem); - if (rc) + if (rem) return BLK_STS_IOERR; len -= chunk; off = 0; diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 04a20da76786..c8b30067b6ae 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -357,7 +357,7 @@ static void nvme_free_ns_head(struct kref *ref) nvme_mpath_remove_disk(head); ida_simple_remove(&head->subsys->ns_ida, head->instance); list_del_init(&head->entry); - cleanup_srcu_struct(&head->srcu); + cleanup_srcu_struct_quiesced(&head->srcu); nvme_put_subsystem(head->subsys); kfree(head); } diff --git a/drivers/of/device.c b/drivers/of/device.c index 064c818105bd..33d85511d790 100644 --- a/drivers/of/device.c +++ b/drivers/of/device.c @@ -76,6 +76,8 @@ int of_device_add(struct platform_device *ofdev) * of_dma_configure - Setup DMA configuration * @dev: Device to apply DMA configuration * @np: Pointer to OF node having DMA configuration + * @force_dma: Whether device is to be set up by of_dma_configure() even if + * DMA capability is not explicitly described by firmware. * * Try to get devices's DMA configuration from DT and update it * accordingly. @@ -84,7 +86,7 @@ int of_device_add(struct platform_device *ofdev) * can use a platform bus notifier and handle BUS_NOTIFY_ADD_DEVICE events * to fix up DMA configuration. */ -int of_dma_configure(struct device *dev, struct device_node *np) +int of_dma_configure(struct device *dev, struct device_node *np, bool force_dma) { u64 dma_addr, paddr, size = 0; int ret; @@ -100,7 +102,7 @@ int of_dma_configure(struct device *dev, struct device_node *np) * DMA configuration regardless of whether "dma-ranges" is * correctly specified or not. */ - if (!dev->bus->force_dma) + if (!force_dma) return ret == -ENODEV ? 0 : ret; dma_addr = offset = 0; diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c index 9a4f4246231d..895c83e0c7b6 100644 --- a/drivers/of/of_reserved_mem.c +++ b/drivers/of/of_reserved_mem.c @@ -353,7 +353,7 @@ int of_reserved_mem_device_init_by_idx(struct device *dev, /* ensure that dma_ops is set for virtual devices * using reserved memory */ - of_dma_configure(dev, np); + of_dma_configure(dev, np, true); dev_info(dev, "assigned reserved memory node %s\n", rmem->name); } else { diff --git a/drivers/parisc/Kconfig b/drivers/parisc/Kconfig index 3a102a84d637..5a48b5606110 100644 --- a/drivers/parisc/Kconfig +++ b/drivers/parisc/Kconfig @@ -103,11 +103,6 @@ config IOMMU_SBA depends on PCI_LBA default PCI_LBA -config IOMMU_HELPER - bool - depends on IOMMU_SBA || IOMMU_CCIO - default y - source "drivers/pcmcia/Kconfig" endmenu diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c index d29cedb3f23b..614823617b8b 100644 --- a/drivers/parisc/ccio-dma.c +++ b/drivers/parisc/ccio-dma.c @@ -1570,8 +1570,6 @@ static int __init ccio_probe(struct parisc_device *dev) } #endif ioc_count++; - - parisc_has_iommu(); return 0; } diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index 0d33d1f86d10..11de0eccf968 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -1989,8 +1989,6 @@ static int __init sba_driver_callback(struct parisc_device *dev) proc_create_single("sba_iommu", 0, root, sba_proc_info); proc_create_single("sba_iommu-bitmap", 0, root, sba_proc_bitmap_info); #endif - - parisc_has_iommu(); return 0; } diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 34b56a8f8480..29a487f31dae 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -5,10 +5,6 @@ source "drivers/pci/pcie/Kconfig" -config PCI_BUS_ADDR_T_64BIT - def_bool y if (ARCH_DMA_ADDR_T_64BIT || 64BIT) - depends on PCI - config PCI_MSI bool "Message Signaled Interrupts (MSI and MSI-X)" depends on PCI diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index bc2ded4c451f..35b7fc87eac5 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -120,7 +120,7 @@ int devm_request_pci_bus_resources(struct device *dev, EXPORT_SYMBOL_GPL(devm_request_pci_bus_resources); static struct pci_bus_region pci_32_bit = {0, 0xffffffffULL}; -#ifdef CONFIG_PCI_BUS_ADDR_T_64BIT +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT static struct pci_bus_region pci_64_bit = {0, (pci_bus_addr_t) 0xffffffffffffffffULL}; static struct pci_bus_region pci_high = {(pci_bus_addr_t) 0x100000000ULL, @@ -230,7 +230,7 @@ int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, resource_size_t), void *alignf_data) { -#ifdef CONFIG_PCI_BUS_ADDR_T_64BIT +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT int rc; if (res->flags & IORESOURCE_MEM_64) { diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 30250631efe7..f45b74fcc059 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -1434,6 +1434,9 @@ struct irq_domain *pci_msi_create_irq_domain(struct fwnode_handle *fwnode, { struct irq_domain *domain; + if (WARN_ON(info->flags & MSI_FLAG_LEVEL_CAPABLE)) + info->flags &= ~MSI_FLAG_LEVEL_CAPABLE; + if (info->flags & MSI_FLAG_USE_DEF_DOM_OPS) pci_msi_domain_update_dom_ops(info); if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index b9a131137e64..f8269a725667 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -16,6 +16,8 @@ #include <linux/pm_runtime.h> #include <linux/suspend.h> #include <linux/kexec.h> +#include <linux/of_device.h> +#include <linux/acpi.h> #include "pci.h" #include "pcie/portdrv.h" @@ -1577,6 +1579,35 @@ static int pci_bus_num_vf(struct device *dev) return pci_num_vf(to_pci_dev(dev)); } +/** + * pci_dma_configure - Setup DMA configuration + * @dev: ptr to dev structure + * + * Function to update PCI devices's DMA configuration using the same + * info from the OF node or ACPI node of host bridge's parent (if any). + */ +static int pci_dma_configure(struct device *dev) +{ + struct device *bridge; + int ret = 0; + + bridge = pci_get_host_bridge_device(to_pci_dev(dev)); + + if (IS_ENABLED(CONFIG_OF) && bridge->parent && + bridge->parent->of_node) { + ret = of_dma_configure(dev, bridge->parent->of_node, true); + } else if (has_acpi_companion(bridge)) { + struct acpi_device *adev = to_acpi_device_node(bridge->fwnode); + enum dev_dma_attr attr = acpi_get_dma_attr(adev); + + if (attr != DEV_DMA_NOT_SUPPORTED) + ret = acpi_dma_configure(dev, attr); + } + + pci_put_host_bridge_device(bridge); + return ret; +} + struct bus_type pci_bus_type = { .name = "pci", .match = pci_bus_match, @@ -1589,7 +1620,7 @@ struct bus_type pci_bus_type = { .drv_groups = pci_drv_groups, .pm = PCI_PM_OPS_PTR, .num_vf = pci_bus_num_vf, - .force_dma = true, + .dma_configure = pci_dma_configure, }; EXPORT_SYMBOL(pci_bus_type); diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.c b/drivers/pinctrl/stm32/pinctrl-stm32.c index 6cbcff42ba47..dfed60982a8a 100644 --- a/drivers/pinctrl/stm32/pinctrl-stm32.c +++ b/drivers/pinctrl/stm32/pinctrl-stm32.c @@ -267,12 +267,13 @@ static void stm32_gpio_irq_release_resources(struct irq_data *irq_data) } static struct irq_chip stm32_gpio_irq_chip = { - .name = "stm32gpio", - .irq_ack = irq_chip_ack_parent, - .irq_mask = irq_chip_mask_parent, - .irq_unmask = irq_chip_unmask_parent, - .irq_set_type = irq_chip_set_type_parent, - .irq_set_wake = irq_chip_set_wake_parent, + .name = "stm32gpio", + .irq_eoi = irq_chip_eoi_parent, + .irq_ack = irq_chip_ack_parent, + .irq_mask = irq_chip_mask_parent, + .irq_unmask = irq_chip_unmask_parent, + .irq_set_type = irq_chip_set_type_parent, + .irq_set_wake = irq_chip_set_wake_parent, .irq_request_resources = stm32_gpio_irq_request_resources, .irq_release_resources = stm32_gpio_irq_release_resources, }; diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig index e728a96cabfd..cb0df9eb3e0f 100644 --- a/drivers/platform/chrome/Kconfig +++ b/drivers/platform/chrome/Kconfig @@ -38,6 +38,17 @@ config CHROMEOS_PSTORE If you have a supported Chromebook, choose Y or M here. The module will be called chromeos_pstore. +config CHROMEOS_TBMC + tristate "ChromeOS Tablet Switch Controller" + depends on ACPI + depends on INPUT + help + This option adds a driver for the tablet switch on + select Chrome OS systems. + + To compile this driver as a module, choose M here: the + module will be called chromeos_tbmc. + config CROS_EC_CTL tristate diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile index ff3b369911f0..e44c37a63fa9 100644 --- a/drivers/platform/chrome/Makefile +++ b/drivers/platform/chrome/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_CHROMEOS_LAPTOP) += chromeos_laptop.o obj-$(CONFIG_CHROMEOS_PSTORE) += chromeos_pstore.o +obj-$(CONFIG_CHROMEOS_TBMC) += chromeos_tbmc.o cros_ec_ctl-objs := cros_ec_sysfs.o cros_ec_lightbar.o \ cros_ec_vbc.o cros_ec_debugfs.o obj-$(CONFIG_CROS_EC_CTL) += cros_ec_ctl.o diff --git a/drivers/platform/chrome/chromeos_laptop.c b/drivers/platform/chrome/chromeos_laptop.c index 5c47f451e43b..24326eecd787 100644 --- a/drivers/platform/chrome/chromeos_laptop.c +++ b/drivers/platform/chrome/chromeos_laptop.c @@ -6,6 +6,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/acpi.h> #include <linux/dmi.h> #include <linux/i2c.h> #include <linux/input.h> @@ -54,6 +55,11 @@ struct i2c_peripheral { struct i2c_client *client; }; +struct acpi_peripheral { + char hid[ACPI_ID_LEN]; + const struct property_entry *properties; +}; + struct chromeos_laptop { /* * Note that we can't mark this pointer as const because @@ -61,6 +67,9 @@ struct chromeos_laptop { */ struct i2c_peripheral *i2c_peripherals; unsigned int num_i2c_peripherals; + + const struct acpi_peripheral *acpi_peripherals; + unsigned int num_acpi_peripherals; }; static const struct chromeos_laptop *cros_laptop; @@ -148,6 +157,38 @@ static void chromeos_laptop_check_adapter(struct i2c_adapter *adapter) } } +static bool chromeos_laptop_adjust_client(struct i2c_client *client) +{ + const struct acpi_peripheral *acpi_dev; + struct acpi_device_id acpi_ids[2] = { }; + int i; + int error; + + if (!has_acpi_companion(&client->dev)) + return false; + + for (i = 0; i < cros_laptop->num_acpi_peripherals; i++) { + acpi_dev = &cros_laptop->acpi_peripherals[i]; + + memcpy(acpi_ids[0].id, acpi_dev->hid, ACPI_ID_LEN); + + if (acpi_match_device(acpi_ids, &client->dev)) { + error = device_add_properties(&client->dev, + acpi_dev->properties); + if (error) { + dev_err(&client->dev, + "failed to add properties: %d\n", + error); + break; + } + + return true; + } + } + + return false; +} + static void chromeos_laptop_detach_i2c_client(struct i2c_client *client) { struct i2c_peripheral *i2c_dev; @@ -170,6 +211,8 @@ static int chromeos_laptop_i2c_notifier_call(struct notifier_block *nb, case BUS_NOTIFY_ADD_DEVICE: if (dev->type == &i2c_adapter_type) chromeos_laptop_check_adapter(to_i2c_adapter(dev)); + else if (dev->type == &i2c_client_type) + chromeos_laptop_adjust_client(to_i2c_client(dev)); break; case BUS_NOTIFY_REMOVED_DEVICE: @@ -191,6 +234,12 @@ static const struct chromeos_laptop _name __initconst = { \ .num_i2c_peripherals = ARRAY_SIZE(_name##_peripherals), \ } +#define DECLARE_ACPI_CROS_LAPTOP(_name) \ +static const struct chromeos_laptop _name __initconst = { \ + .acpi_peripherals = _name##_peripherals, \ + .num_acpi_peripherals = ARRAY_SIZE(_name##_peripherals), \ +} + static struct i2c_peripheral samsung_series_5_550_peripherals[] __initdata = { /* Touchpad. */ { @@ -234,16 +283,25 @@ static const int chromebook_pixel_tp_keys[] __initconst = { static const struct property_entry chromebook_pixel_trackpad_props[] __initconst = { + PROPERTY_ENTRY_STRING("compatible", "atmel,maxtouch"), PROPERTY_ENTRY_U32_ARRAY("linux,gpio-keymap", chromebook_pixel_tp_keys), { } }; +static const struct property_entry +chromebook_atmel_touchscreen_props[] __initconst = { + PROPERTY_ENTRY_STRING("compatible", "atmel,maxtouch"), + { } +}; + static struct i2c_peripheral chromebook_pixel_peripherals[] __initdata = { /* Touch Screen. */ { .board_info = { I2C_BOARD_INFO("atmel_mxt_ts", ATMEL_TS_I2C_ADDR), + .properties = + chromebook_atmel_touchscreen_props, .flags = I2C_CLIENT_WAKE, }, .dmi_name = "touchscreen", @@ -354,6 +412,8 @@ static struct i2c_peripheral acer_c720_peripherals[] __initdata = { .board_info = { I2C_BOARD_INFO("atmel_mxt_ts", ATMEL_TS_I2C_ADDR), + .properties = + chromebook_atmel_touchscreen_props, .flags = I2C_CLIENT_WAKE, }, .dmi_name = "touchscreen", @@ -419,6 +479,47 @@ static struct i2c_peripheral cr48_peripherals[] __initdata = { }; DECLARE_CROS_LAPTOP(cr48); +static const u32 samus_touchpad_buttons[] __initconst = { + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + BTN_LEFT +}; + +static const struct property_entry samus_trackpad_props[] __initconst = { + PROPERTY_ENTRY_STRING("compatible", "atmel,maxtouch"), + PROPERTY_ENTRY_U32_ARRAY("linux,gpio-keymap", samus_touchpad_buttons), + { } +}; + +static struct acpi_peripheral samus_peripherals[] __initdata = { + /* Touchpad */ + { + .hid = "ATML0000", + .properties = samus_trackpad_props, + }, + /* Touchsceen */ + { + .hid = "ATML0001", + .properties = chromebook_atmel_touchscreen_props, + }, +}; +DECLARE_ACPI_CROS_LAPTOP(samus); + +static struct acpi_peripheral generic_atmel_peripherals[] __initdata = { + /* Touchpad */ + { + .hid = "ATML0000", + .properties = chromebook_pixel_trackpad_props, + }, + /* Touchsceen */ + { + .hid = "ATML0001", + .properties = chromebook_atmel_touchscreen_props, + }, +}; +DECLARE_ACPI_CROS_LAPTOP(generic_atmel); + static const struct dmi_system_id chromeos_laptop_dmi_table[] __initconst = { { .ident = "Samsung Series 5 550", @@ -502,17 +603,72 @@ static const struct dmi_system_id chromeos_laptop_dmi_table[] __initconst = { }, .driver_data = (void *)&cr48, }, + /* Devices with peripherals incompletely described in ACPI */ + { + .ident = "Chromebook Pro", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + DMI_MATCH(DMI_PRODUCT_NAME, "Caroline"), + }, + .driver_data = (void *)&samus, + }, + { + .ident = "Google Pixel 2 (2015)", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"), + DMI_MATCH(DMI_PRODUCT_NAME, "Samus"), + }, + .driver_data = (void *)&samus, + }, + { + .ident = "Samsung Chromebook 3", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"), + DMI_MATCH(DMI_PRODUCT_NAME, "Celes"), + }, + .driver_data = (void *)&samus, + }, + { + /* + * Other Chromebooks with Atmel touch controllers: + * - Winky (touchpad) + * - Clapper, Expresso, Rambi, Glimmer (touchscreen) + */ + .ident = "Other Chromebook", + .matches = { + /* + * This will match all Google devices, not only devices + * with Atmel, but we will validate that the device + * actually has matching peripherals. + */ + DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"), + }, + .driver_data = (void *)&generic_atmel, + }, { } }; MODULE_DEVICE_TABLE(dmi, chromeos_laptop_dmi_table); -static int __init chromeos_laptop_scan_adapter(struct device *dev, void *data) +static int __init chromeos_laptop_scan_peripherals(struct device *dev, void *data) { - struct i2c_adapter *adapter; + int error; - adapter = i2c_verify_adapter(dev); - if (adapter) - chromeos_laptop_check_adapter(adapter); + if (dev->type == &i2c_adapter_type) { + chromeos_laptop_check_adapter(to_i2c_adapter(dev)); + } else if (dev->type == &i2c_client_type) { + if (chromeos_laptop_adjust_client(to_i2c_client(dev))) { + /* + * Now that we have needed properties re-trigger + * driver probe in case driver was initialized + * earlier and probe failed. + */ + error = device_attach(dev); + if (error < 0) + dev_warn(dev, + "%s: device_attach() failed: %d\n", + __func__, error); + } + } return 0; } @@ -556,27 +712,24 @@ static int __init chromeos_laptop_setup_irq(struct i2c_peripheral *i2c_dev) return 0; } -static struct chromeos_laptop * __init -chromeos_laptop_prepare(const struct chromeos_laptop *src) +static int __init +chromeos_laptop_prepare_i2c_peripherals(struct chromeos_laptop *cros_laptop, + const struct chromeos_laptop *src) { - struct chromeos_laptop *cros_laptop; struct i2c_peripheral *i2c_dev; struct i2c_board_info *info; - int error; int i; + int error; - cros_laptop = kzalloc(sizeof(*cros_laptop), GFP_KERNEL); - if (!cros_laptop) - return ERR_PTR(-ENOMEM); + if (!src->num_i2c_peripherals) + return 0; cros_laptop->i2c_peripherals = kmemdup(src->i2c_peripherals, src->num_i2c_peripherals * sizeof(*src->i2c_peripherals), GFP_KERNEL); - if (!cros_laptop->i2c_peripherals) { - error = -ENOMEM; - goto err_free_cros_laptop; - } + if (!cros_laptop->i2c_peripherals) + return -ENOMEM; cros_laptop->num_i2c_peripherals = src->num_i2c_peripherals; @@ -586,7 +739,7 @@ chromeos_laptop_prepare(const struct chromeos_laptop *src) error = chromeos_laptop_setup_irq(i2c_dev); if (error) - goto err_destroy_cros_peripherals; + goto err_out; /* We need to deep-copy properties */ if (info->properties) { @@ -594,14 +747,14 @@ chromeos_laptop_prepare(const struct chromeos_laptop *src) property_entries_dup(info->properties); if (IS_ERR(info->properties)) { error = PTR_ERR(info->properties); - goto err_destroy_cros_peripherals; + goto err_out; } } } - return cros_laptop; + return 0; -err_destroy_cros_peripherals: +err_out: while (--i >= 0) { i2c_dev = &cros_laptop->i2c_peripherals[i]; info = &i2c_dev->board_info; @@ -609,13 +762,74 @@ err_destroy_cros_peripherals: property_entries_free(info->properties); } kfree(cros_laptop->i2c_peripherals); -err_free_cros_laptop: - kfree(cros_laptop); - return ERR_PTR(error); + return error; +} + +static int __init +chromeos_laptop_prepare_acpi_peripherals(struct chromeos_laptop *cros_laptop, + const struct chromeos_laptop *src) +{ + struct acpi_peripheral *acpi_peripherals; + struct acpi_peripheral *acpi_dev; + const struct acpi_peripheral *src_dev; + int n_peripherals = 0; + int i; + int error; + + for (i = 0; i < src->num_acpi_peripherals; i++) { + if (acpi_dev_present(src->acpi_peripherals[i].hid, NULL, -1)) + n_peripherals++; + } + + if (!n_peripherals) + return 0; + + acpi_peripherals = kcalloc(n_peripherals, + sizeof(*src->acpi_peripherals), + GFP_KERNEL); + if (!acpi_peripherals) + return -ENOMEM; + + acpi_dev = acpi_peripherals; + for (i = 0; i < src->num_acpi_peripherals; i++) { + src_dev = &src->acpi_peripherals[i]; + if (!acpi_dev_present(src_dev->hid, NULL, -1)) + continue; + + *acpi_dev = *src_dev; + + /* We need to deep-copy properties */ + if (src_dev->properties) { + acpi_dev->properties = + property_entries_dup(src_dev->properties); + if (IS_ERR(acpi_dev->properties)) { + error = PTR_ERR(acpi_dev->properties); + goto err_out; + } + } + + acpi_dev++; + } + + cros_laptop->acpi_peripherals = acpi_peripherals; + cros_laptop->num_acpi_peripherals = n_peripherals; + + return 0; + +err_out: + while (--i >= 0) { + acpi_dev = &acpi_peripherals[i]; + if (acpi_dev->properties) + property_entries_free(acpi_dev->properties); + } + + kfree(acpi_peripherals); + return error; } static void chromeos_laptop_destroy(const struct chromeos_laptop *cros_laptop) { + const struct acpi_peripheral *acpi_dev; struct i2c_peripheral *i2c_dev; struct i2c_board_info *info; int i; @@ -631,10 +845,41 @@ static void chromeos_laptop_destroy(const struct chromeos_laptop *cros_laptop) property_entries_free(info->properties); } + for (i = 0; i < cros_laptop->num_acpi_peripherals; i++) { + acpi_dev = &cros_laptop->acpi_peripherals[i]; + + if (acpi_dev->properties) + property_entries_free(acpi_dev->properties); + } + kfree(cros_laptop->i2c_peripherals); + kfree(cros_laptop->acpi_peripherals); kfree(cros_laptop); } +static struct chromeos_laptop * __init +chromeos_laptop_prepare(const struct chromeos_laptop *src) +{ + struct chromeos_laptop *cros_laptop; + int error; + + cros_laptop = kzalloc(sizeof(*cros_laptop), GFP_KERNEL); + if (!cros_laptop) + return ERR_PTR(-ENOMEM); + + error = chromeos_laptop_prepare_i2c_peripherals(cros_laptop, src); + if (!error) + error = chromeos_laptop_prepare_acpi_peripherals(cros_laptop, + src); + + if (error) { + chromeos_laptop_destroy(cros_laptop); + return ERR_PTR(error); + } + + return cros_laptop; +} + static int __init chromeos_laptop_init(void) { const struct dmi_system_id *dmi_id; @@ -652,21 +897,33 @@ static int __init chromeos_laptop_init(void) if (IS_ERR(cros_laptop)) return PTR_ERR(cros_laptop); + if (!cros_laptop->num_i2c_peripherals && + !cros_laptop->num_acpi_peripherals) { + pr_debug("no relevant devices detected\n"); + error = -ENODEV; + goto err_destroy_cros_laptop; + } + error = bus_register_notifier(&i2c_bus_type, &chromeos_laptop_i2c_notifier); if (error) { - pr_err("failed to register i2c bus notifier: %d\n", error); - chromeos_laptop_destroy(cros_laptop); - return error; + pr_err("failed to register i2c bus notifier: %d\n", + error); + goto err_destroy_cros_laptop; } /* - * Scan adapters that have been registered before we installed - * the notifier to make sure we do not miss any devices. + * Scan adapters that have been registered and clients that have + * been created before we installed the notifier to make sure + * we do not miss any devices. */ - i2c_for_each_dev(NULL, chromeos_laptop_scan_adapter); + i2c_for_each_dev(NULL, chromeos_laptop_scan_peripherals); return 0; + +err_destroy_cros_laptop: + chromeos_laptop_destroy(cros_laptop); + return error; } static void __exit chromeos_laptop_exit(void) diff --git a/drivers/platform/chrome/chromeos_tbmc.c b/drivers/platform/chrome/chromeos_tbmc.c new file mode 100644 index 000000000000..b935df6a9694 --- /dev/null +++ b/drivers/platform/chrome/chromeos_tbmc.c @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Driver to detect Tablet Mode for ChromeOS convertible. +// +// Copyright (C) 2017 Google, Inc. +// Author: Gwendal Grignou <gwendal@chromium.org> + +#include <linux/acpi.h> +#include <linux/input.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/printk.h> + +#define DRV_NAME "chromeos_tbmc" +#define ACPI_DRV_NAME "GOOG0006" + +static int chromeos_tbmc_query_switch(struct acpi_device *adev, + struct input_dev *idev) +{ + unsigned long long state; + acpi_status status; + + status = acpi_evaluate_integer(adev->handle, "TBMC", NULL, &state); + if (ACPI_FAILURE(status)) + return -ENODEV; + + /* input layer checks if event is redundant */ + input_report_switch(idev, SW_TABLET_MODE, state); + input_sync(idev); + + return 0; +} + +static __maybe_unused int chromeos_tbmc_resume(struct device *dev) +{ + struct acpi_device *adev = to_acpi_device(dev); + + return chromeos_tbmc_query_switch(adev, adev->driver_data); +} + +static void chromeos_tbmc_notify(struct acpi_device *adev, u32 event) +{ + switch (event) { + case 0x80: + chromeos_tbmc_query_switch(adev, adev->driver_data); + break; + default: + dev_err(&adev->dev, "Unexpected event: 0x%08X\n", event); + } +} + +static int chromeos_tbmc_open(struct input_dev *idev) +{ + struct acpi_device *adev = input_get_drvdata(idev); + + return chromeos_tbmc_query_switch(adev, idev); +} + +static int chromeos_tbmc_add(struct acpi_device *adev) +{ + struct input_dev *idev; + struct device *dev = &adev->dev; + int ret; + + idev = devm_input_allocate_device(dev); + if (!idev) + return -ENOMEM; + + idev->name = "Tablet Mode Switch"; + idev->phys = acpi_device_hid(adev); + + idev->id.bustype = BUS_HOST; + idev->id.version = 1; + idev->id.product = 0; + idev->open = chromeos_tbmc_open; + + input_set_drvdata(idev, adev); + adev->driver_data = idev; + + input_set_capability(idev, EV_SW, SW_TABLET_MODE); + ret = input_register_device(idev); + if (ret) { + dev_err(dev, "cannot register input device\n"); + return ret; + } + return 0; +} + +static const struct acpi_device_id chromeos_tbmc_acpi_device_ids[] = { + { ACPI_DRV_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(acpi, chromeos_tbmc_acpi_device_ids); + +static const SIMPLE_DEV_PM_OPS(chromeos_tbmc_pm_ops, NULL, + chromeos_tbmc_resume); + +static struct acpi_driver chromeos_tbmc_driver = { + .name = DRV_NAME, + .class = DRV_NAME, + .ids = chromeos_tbmc_acpi_device_ids, + .ops = { + .add = chromeos_tbmc_add, + .notify = chromeos_tbmc_notify, + }, + .drv.pm = &chromeos_tbmc_pm_ops, +}; + +module_acpi_driver(chromeos_tbmc_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("ChromeOS ACPI tablet switch driver"); diff --git a/drivers/platform/chrome/cros_ec_lightbar.c b/drivers/platform/chrome/cros_ec_lightbar.c index 6ea79d495aa2..68193bb53383 100644 --- a/drivers/platform/chrome/cros_ec_lightbar.c +++ b/drivers/platform/chrome/cros_ec_lightbar.c @@ -170,8 +170,7 @@ static ssize_t version_show(struct device *dev, struct device_attribute *attr, char *buf) { uint32_t version = 0, flags = 0; - struct cros_ec_dev *ec = container_of(dev, - struct cros_ec_dev, class_dev); + struct cros_ec_dev *ec = to_cros_ec_dev(dev); int ret; ret = lb_throttle(); @@ -193,8 +192,7 @@ static ssize_t brightness_store(struct device *dev, struct cros_ec_command *msg; int ret; unsigned int val; - struct cros_ec_dev *ec = container_of(dev, - struct cros_ec_dev, class_dev); + struct cros_ec_dev *ec = to_cros_ec_dev(dev); if (kstrtouint(buf, 0, &val)) return -EINVAL; @@ -238,8 +236,7 @@ static ssize_t led_rgb_store(struct device *dev, struct device_attribute *attr, { struct ec_params_lightbar *param; struct cros_ec_command *msg; - struct cros_ec_dev *ec = container_of(dev, - struct cros_ec_dev, class_dev); + struct cros_ec_dev *ec = to_cros_ec_dev(dev); unsigned int val[4]; int ret, i = 0, j = 0, ok = 0; @@ -311,8 +308,7 @@ static ssize_t sequence_show(struct device *dev, struct ec_response_lightbar *resp; struct cros_ec_command *msg; int ret; - struct cros_ec_dev *ec = container_of(dev, - struct cros_ec_dev, class_dev); + struct cros_ec_dev *ec = to_cros_ec_dev(dev); msg = alloc_lightbar_cmd_msg(ec); if (!msg) @@ -439,8 +435,7 @@ static ssize_t sequence_store(struct device *dev, struct device_attribute *attr, struct cros_ec_command *msg; unsigned int num; int ret, len; - struct cros_ec_dev *ec = container_of(dev, - struct cros_ec_dev, class_dev); + struct cros_ec_dev *ec = to_cros_ec_dev(dev); for (len = 0; len < count; len++) if (!isalnum(buf[len])) @@ -488,8 +483,7 @@ static ssize_t program_store(struct device *dev, struct device_attribute *attr, int extra_bytes, max_size, ret; struct ec_params_lightbar *param; struct cros_ec_command *msg; - struct cros_ec_dev *ec = container_of(dev, struct cros_ec_dev, - class_dev); + struct cros_ec_dev *ec = to_cros_ec_dev(dev); /* * We might need to reject the program for size reasons. The EC @@ -599,8 +593,7 @@ static umode_t cros_ec_lightbar_attrs_are_visible(struct kobject *kobj, struct attribute *a, int n) { struct device *dev = container_of(kobj, struct device, kobj); - struct cros_ec_dev *ec = container_of(dev, - struct cros_ec_dev, class_dev); + struct cros_ec_dev *ec = to_cros_ec_dev(dev); struct platform_device *pdev = to_platform_device(ec->dev); struct cros_ec_platform *pdata = pdev->dev.platform_data; int is_cros_ec; diff --git a/drivers/platform/chrome/cros_ec_lpc.c b/drivers/platform/chrome/cros_ec_lpc.c index 3682e1539251..31c8b8c49e45 100644 --- a/drivers/platform/chrome/cros_ec_lpc.c +++ b/drivers/platform/chrome/cros_ec_lpc.c @@ -435,7 +435,13 @@ static int __init cros_ec_lpc_init(void) int ret; acpi_status status; - if (!dmi_check_system(cros_ec_lpc_dmi_table)) { + status = acpi_get_devices(ACPI_DRV_NAME, cros_ec_lpc_parse_device, + &cros_ec_lpc_acpi_device_found, NULL); + if (ACPI_FAILURE(status)) + pr_warn(DRV_NAME ": Looking for %s failed\n", ACPI_DRV_NAME); + + if (!cros_ec_lpc_acpi_device_found && + !dmi_check_system(cros_ec_lpc_dmi_table)) { pr_err(DRV_NAME ": unsupported system.\n"); return -ENODEV; } @@ -450,11 +456,6 @@ static int __init cros_ec_lpc_init(void) return ret; } - status = acpi_get_devices(ACPI_DRV_NAME, cros_ec_lpc_parse_device, - &cros_ec_lpc_acpi_device_found, NULL); - if (ACPI_FAILURE(status)) - pr_warn(DRV_NAME ": Looking for %s failed\n", ACPI_DRV_NAME); - if (!cros_ec_lpc_acpi_device_found) { /* Register the device, and it'll get hooked up automatically */ ret = platform_device_register(&cros_ec_lpc_device); diff --git a/drivers/platform/chrome/cros_ec_sysfs.c b/drivers/platform/chrome/cros_ec_sysfs.c index 5a6db3fe213a..f34a50121064 100644 --- a/drivers/platform/chrome/cros_ec_sysfs.c +++ b/drivers/platform/chrome/cros_ec_sysfs.c @@ -34,8 +34,6 @@ #include <linux/types.h> #include <linux/uaccess.h> -#define to_cros_ec_dev(dev) container_of(dev, struct cros_ec_dev, class_dev) - /* Accessor functions */ static ssize_t reboot_show(struct device *dev, diff --git a/drivers/platform/chrome/cros_ec_vbc.c b/drivers/platform/chrome/cros_ec_vbc.c index 6d38e6b08334..5356f26bc022 100644 --- a/drivers/platform/chrome/cros_ec_vbc.c +++ b/drivers/platform/chrome/cros_ec_vbc.c @@ -29,8 +29,7 @@ static ssize_t vboot_context_read(struct file *filp, struct kobject *kobj, loff_t pos, size_t count) { struct device *dev = container_of(kobj, struct device, kobj); - struct cros_ec_dev *ec = container_of(dev, struct cros_ec_dev, - class_dev); + struct cros_ec_dev *ec = to_cros_ec_dev(dev); struct cros_ec_device *ecdev = ec->ec_dev; struct ec_params_vbnvcontext *params; struct cros_ec_command *msg; @@ -70,8 +69,7 @@ static ssize_t vboot_context_write(struct file *filp, struct kobject *kobj, loff_t pos, size_t count) { struct device *dev = container_of(kobj, struct device, kobj); - struct cros_ec_dev *ec = container_of(dev, struct cros_ec_dev, - class_dev); + struct cros_ec_dev *ec = to_cros_ec_dev(dev); struct cros_ec_device *ecdev = ec->ec_dev; struct ec_params_vbnvcontext *params; struct cros_ec_command *msg; @@ -111,8 +109,7 @@ static umode_t cros_ec_vbc_is_visible(struct kobject *kobj, struct bin_attribute *a, int n) { struct device *dev = container_of(kobj, struct device, kobj); - struct cros_ec_dev *ec = container_of(dev, struct cros_ec_dev, - class_dev); + struct cros_ec_dev *ec = to_cros_ec_dev(dev); struct device_node *np = ec->ec_dev->dev->of_node; if (IS_ENABLED(CONFIG_OF) && np) { diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index 7bdc6aaa0ba3..2016e0ed5865 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c @@ -18,7 +18,6 @@ #include <linux/fs.h> #include <linux/blkpg.h> #include <linux/slab.h> -#include <asm/compat.h> #include <asm/ccwdev.h> #include <asm/schid.h> #include <asm/cmb.h> diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c index 61822480a2a0..16a4e8528bbc 100644 --- a/drivers/s390/char/fs3270.c +++ b/drivers/s390/char/fs3270.c @@ -19,7 +19,6 @@ #include <linux/slab.h> #include <linux/types.h> -#include <asm/compat.h> #include <asm/ccwdev.h> #include <asm/cio.h> #include <asm/ebcdic.h> diff --git a/drivers/s390/char/sclp_ctl.c b/drivers/s390/char/sclp_ctl.c index a78cea0c3a09..248b5db3eaa8 100644 --- a/drivers/s390/char/sclp_ctl.c +++ b/drivers/s390/char/sclp_ctl.c @@ -14,7 +14,6 @@ #include <linux/init.h> #include <linux/ioctl.h> #include <linux/fs.h> -#include <asm/compat.h> #include <asm/sclp_ctl.h> #include <asm/sclp.h> diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c index 17e411c57576..948ce82a7725 100644 --- a/drivers/s390/char/vmcp.c +++ b/drivers/s390/char/vmcp.c @@ -23,7 +23,6 @@ #include <linux/mutex.h> #include <linux/cma.h> #include <linux/mm.h> -#include <asm/compat.h> #include <asm/cpcmd.h> #include <asm/debug.h> #include <asm/vmcp.h> diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c index 0015729d917d..8d9f36625ba5 100644 --- a/drivers/s390/cio/chsc_sch.c +++ b/drivers/s390/cio/chsc_sch.c @@ -16,7 +16,6 @@ #include <linux/miscdevice.h> #include <linux/kernel_stat.h> -#include <asm/compat.h> #include <asm/cio.h> #include <asm/chsc.h> #include <asm/isc.h> diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index dffd820731f2..f5a0d894d9ad 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -10,6 +10,7 @@ #define KMSG_COMPONENT "qeth" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt +#include <linux/compat.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/string.h> @@ -32,7 +33,6 @@ #include <asm/chpid.h> #include <asm/io.h> #include <asm/sysinfo.h> -#include <asm/compat.h> #include <asm/diag.h> #include <asm/cio.h> #include <asm/ccwdev.h> diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index f125fd71c0f2..fb38aeff9dbd 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -2149,27 +2149,6 @@ static int scsi_map_queues(struct blk_mq_tag_set *set) return blk_mq_map_queues(set); } -static u64 scsi_calculate_bounce_limit(struct Scsi_Host *shost) -{ - struct device *host_dev; - u64 bounce_limit = 0xffffffff; - - if (shost->unchecked_isa_dma) - return BLK_BOUNCE_ISA; - /* - * Platforms with virtual-DMA translation - * hardware have no practical limit. - */ - if (!PCI_DMA_BUS_IS_PHYS) - return BLK_BOUNCE_ANY; - - host_dev = scsi_get_device(shost); - if (host_dev && host_dev->dma_mask) - bounce_limit = (u64)dma_max_pfn(host_dev) << PAGE_SHIFT; - - return bounce_limit; -} - void __scsi_init_queue(struct Scsi_Host *shost, struct request_queue *q) { struct device *dev = shost->dma_dev; @@ -2189,7 +2168,8 @@ void __scsi_init_queue(struct Scsi_Host *shost, struct request_queue *q) } blk_queue_max_hw_sectors(q, shost->max_sectors); - blk_queue_bounce_limit(q, scsi_calculate_bounce_limit(shost)); + if (shost->unchecked_isa_dma) + blk_queue_bounce_limit(q, BLK_BOUNCE_ISA); blk_queue_segment_boundary(q, shost->dma_boundary); dma_set_seg_boundary(dev, shost->dma_boundary); diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 2d4146ce2f1b..ad5d68e1dab7 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -47,6 +47,13 @@ config SPI_MASTER if SPI_MASTER +config SPI_MEM + bool "SPI memory extension" + help + Enable this option if you want to enable the SPI memory extension. + This extension is meant to simplify interaction with SPI memories + by providing a high-level interface to send memory-like commands. + comment "SPI Master Controller Drivers" config SPI_ALTERA @@ -71,7 +78,6 @@ config SPI_ARMADA_3700 config SPI_ATMEL tristate "Atmel SPI Controller" - depends on HAS_DMA depends on ARCH_AT91 || COMPILE_TEST help This selects a driver for the Atmel SPI Controller, present on @@ -115,14 +121,6 @@ config SPI_BCM2835AUX "universal SPI master", and the regular SPI controller. This driver is for the universal/auxiliary SPI controller. -config SPI_BCM53XX - tristate "Broadcom BCM53xx SPI controller" - depends on ARCH_BCM_5301X - depends on BCMA_POSSIBLE - select BCMA - help - Enable support for the SPI controller on Broadcom BCM53xx ARM SoCs. - config SPI_BCM63XX tristate "Broadcom BCM63xx SPI controller" depends on BCM63XX || COMPILE_TEST @@ -233,7 +231,6 @@ config SPI_EFM32 config SPI_EP93XX tristate "Cirrus Logic EP93xx SPI controller" - depends on HAS_DMA depends on ARCH_EP93XX || COMPILE_TEST help This enables using the Cirrus EP93xx SPI controller in master @@ -355,7 +352,6 @@ config SPI_FSL_SPI config SPI_FSL_DSPI tristate "Freescale DSPI controller" select REGMAP_MMIO - depends on HAS_DMA depends on SOC_VF610 || SOC_LS1021A || ARCH_LAYERSCAPE || M5441x || COMPILE_TEST help This enables support for the Freescale DSPI controller in master @@ -431,7 +427,6 @@ config SPI_OMAP_UWIRE config SPI_OMAP24XX tristate "McSPI driver for OMAP" - depends on HAS_DMA depends on ARCH_OMAP2PLUS || COMPILE_TEST select SG_SPLIT help @@ -440,7 +435,6 @@ config SPI_OMAP24XX config SPI_TI_QSPI tristate "DRA7xxx QSPI controller support" - depends on HAS_DMA depends on ARCH_OMAP2PLUS || COMPILE_TEST help QSPI master controller for DRA7xxx used for flash devices. @@ -469,7 +463,6 @@ config SPI_PIC32 config SPI_PIC32_SQI tristate "Microchip PIC32 Quad SPI driver" depends on MACH_PIC32 || COMPILE_TEST - depends on HAS_DMA help SPI driver for PIC32 Quad SPI controller. @@ -572,7 +565,7 @@ config SPI_SC18IS602 config SPI_SH_MSIOF tristate "SuperH MSIOF SPI controller" - depends on HAVE_CLK && HAS_DMA + depends on HAVE_CLK depends on ARCH_SHMOBILE || ARCH_RENESAS || COMPILE_TEST help SPI driver for SuperH and SH Mobile MSIOF blocks. @@ -650,7 +643,7 @@ config SPI_MXS config SPI_TEGRA114 tristate "NVIDIA Tegra114 SPI Controller" depends on (ARCH_TEGRA && TEGRA20_APB_DMA) || COMPILE_TEST - depends on RESET_CONTROLLER && HAS_DMA + depends on RESET_CONTROLLER help SPI driver for NVIDIA Tegra114 SPI Controller interface. This controller is different than the older SoCs SPI controller and also register interface @@ -668,7 +661,7 @@ config SPI_TEGRA20_SFLASH config SPI_TEGRA20_SLINK tristate "Nvidia Tegra20/Tegra30 SLINK Controller" depends on (ARCH_TEGRA && TEGRA20_APB_DMA) || COMPILE_TEST - depends on RESET_CONTROLLER && HAS_DMA + depends on RESET_CONTROLLER help SPI driver for Nvidia Tegra20/Tegra30 SLINK Controller interface. diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index b935f10eb961..cb1f4378b87c 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -8,6 +8,7 @@ ccflags-$(CONFIG_SPI_DEBUG) := -DDEBUG # small core, mostly translating board-specific # config declarations into driver model code obj-$(CONFIG_SPI_MASTER) += spi.o +obj-$(CONFIG_SPI_MEM) += spi-mem.o obj-$(CONFIG_SPI_SPIDEV) += spidev.o obj-$(CONFIG_SPI_LOOPBACK_TEST) += spi-loopback-test.o @@ -20,7 +21,6 @@ obj-$(CONFIG_SPI_AU1550) += spi-au1550.o obj-$(CONFIG_SPI_AXI_SPI_ENGINE) += spi-axi-spi-engine.o obj-$(CONFIG_SPI_BCM2835) += spi-bcm2835.o obj-$(CONFIG_SPI_BCM2835AUX) += spi-bcm2835aux.o -obj-$(CONFIG_SPI_BCM53XX) += spi-bcm53xx.o obj-$(CONFIG_SPI_BCM63XX) += spi-bcm63xx.o obj-$(CONFIG_SPI_BCM63XX_HSSPI) += spi-bcm63xx-hsspi.o obj-$(CONFIG_SPI_BCM_QSPI) += spi-iproc-qspi.o spi-brcmstb-qspi.o spi-bcm-qspi.o diff --git a/drivers/spi/internals.h b/drivers/spi/internals.h new file mode 100644 index 000000000000..4a28a8395552 --- /dev/null +++ b/drivers/spi/internals.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2018 Exceet Electronics GmbH + * Copyright (C) 2018 Bootlin + * + * Author: Boris Brezillon <boris.brezillon@bootlin.com> + * + * Helpers needed by the spi or spi-mem logic. Should not be used outside of + * spi-mem.c and spi.c. + */ + +#ifndef __LINUX_SPI_INTERNALS_H +#define __LINUX_SPI_INTERNALS_H + +#include <linux/device.h> +#include <linux/dma-direction.h> +#include <linux/scatterlist.h> +#include <linux/spi/spi.h> + +void spi_flush_queue(struct spi_controller *ctrl); + +#ifdef CONFIG_HAS_DMA +int spi_map_buf(struct spi_controller *ctlr, struct device *dev, + struct sg_table *sgt, void *buf, size_t len, + enum dma_data_direction dir); +void spi_unmap_buf(struct spi_controller *ctlr, struct device *dev, + struct sg_table *sgt, enum dma_data_direction dir); +#else /* !CONFIG_HAS_DMA */ +static inline int spi_map_buf(struct spi_controller *ctlr, struct device *dev, + struct sg_table *sgt, void *buf, size_t len, + enum dma_data_direction dir) +{ + return -EINVAL; +} + +static inline void spi_unmap_buf(struct spi_controller *ctlr, + struct device *dev, struct sg_table *sgt, + enum dma_data_direction dir) +{ +} +#endif /* CONFIG_HAS_DMA */ + +#endif /* __LINUX_SPI_INTERNALS_H */ diff --git a/drivers/spi/spi-bcm-qspi.c b/drivers/spi/spi-bcm-qspi.c index 6573152ce893..8612525fa4e3 100644 --- a/drivers/spi/spi-bcm-qspi.c +++ b/drivers/spi/spi-bcm-qspi.c @@ -30,6 +30,7 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/spi/spi.h> +#include <linux/spi/spi-mem.h> #include <linux/sysfs.h> #include <linux/types.h> #include "spi-bcm-qspi.h" @@ -215,10 +216,10 @@ struct bcm_qspi { int bspi_maj_rev; int bspi_min_rev; int bspi_enabled; - struct spi_flash_read_message *bspi_rf_msg; - u32 bspi_rf_msg_idx; - u32 bspi_rf_msg_len; - u32 bspi_rf_msg_status; + const struct spi_mem_op *bspi_rf_op; + u32 bspi_rf_op_idx; + u32 bspi_rf_op_len; + u32 bspi_rf_op_status; struct bcm_xfer_mode xfer_mode; u32 s3_strap_override_ctrl; bool bspi_mode; @@ -313,26 +314,26 @@ static inline void bcm_qspi_bspi_lr_clear(struct bcm_qspi *qspi) static void bcm_qspi_bspi_lr_data_read(struct bcm_qspi *qspi) { - u32 *buf = (u32 *)qspi->bspi_rf_msg->buf; + u32 *buf = (u32 *)qspi->bspi_rf_op->data.buf.in; u32 data = 0; - dev_dbg(&qspi->pdev->dev, "xfer %p rx %p rxlen %d\n", qspi->bspi_rf_msg, - qspi->bspi_rf_msg->buf, qspi->bspi_rf_msg_len); + dev_dbg(&qspi->pdev->dev, "xfer %p rx %p rxlen %d\n", qspi->bspi_rf_op, + qspi->bspi_rf_op->data.buf.in, qspi->bspi_rf_op_len); while (!bcm_qspi_bspi_lr_is_fifo_empty(qspi)) { data = bcm_qspi_bspi_lr_read_fifo(qspi); - if (likely(qspi->bspi_rf_msg_len >= 4) && + if (likely(qspi->bspi_rf_op_len >= 4) && IS_ALIGNED((uintptr_t)buf, 4)) { - buf[qspi->bspi_rf_msg_idx++] = data; - qspi->bspi_rf_msg_len -= 4; + buf[qspi->bspi_rf_op_idx++] = data; + qspi->bspi_rf_op_len -= 4; } else { /* Read out remaining bytes, make sure*/ - u8 *cbuf = (u8 *)&buf[qspi->bspi_rf_msg_idx]; + u8 *cbuf = (u8 *)&buf[qspi->bspi_rf_op_idx]; data = cpu_to_le32(data); - while (qspi->bspi_rf_msg_len) { + while (qspi->bspi_rf_op_len) { *cbuf++ = (u8)data; data >>= 8; - qspi->bspi_rf_msg_len--; + qspi->bspi_rf_op_len--; } } } @@ -349,14 +350,12 @@ static void bcm_qspi_bspi_set_xfer_params(struct bcm_qspi *qspi, u8 cmd_byte, } static int bcm_qspi_bspi_set_flex_mode(struct bcm_qspi *qspi, - struct spi_flash_read_message *msg, - int hp) + const struct spi_mem_op *op, int hp) { int bpc = 0, bpp = 0; - u8 command = msg->read_opcode; - int width = msg->data_nbits ? msg->data_nbits : SPI_NBITS_SINGLE; - int addrlen = msg->addr_width; - int addr_nbits = msg->addr_nbits ? msg->addr_nbits : SPI_NBITS_SINGLE; + u8 command = op->cmd.opcode; + int width = op->cmd.buswidth ? op->cmd.buswidth : SPI_NBITS_SINGLE; + int addrlen = op->addr.nbytes * 8; int flex_mode = 1; dev_dbg(&qspi->pdev->dev, "set flex mode w %x addrlen %x hp %d\n", @@ -365,7 +364,7 @@ static int bcm_qspi_bspi_set_flex_mode(struct bcm_qspi *qspi, if (addrlen == BSPI_ADDRLEN_4BYTES) bpp = BSPI_BPP_ADDR_SELECT_MASK; - bpp |= msg->dummy_bytes * (8/addr_nbits); + bpp |= (op->dummy.nbytes * 8) / op->dummy.buswidth; switch (width) { case SPI_NBITS_SINGLE: @@ -397,11 +396,10 @@ static int bcm_qspi_bspi_set_flex_mode(struct bcm_qspi *qspi, } static int bcm_qspi_bspi_set_override(struct bcm_qspi *qspi, - struct spi_flash_read_message *msg, - int hp) + const struct spi_mem_op *op, int hp) { - int width = msg->data_nbits ? msg->data_nbits : SPI_NBITS_SINGLE; - int addrlen = msg->addr_width; + int width = op->data.buswidth ? op->data.buswidth : SPI_NBITS_SINGLE; + int addrlen = op->addr.nbytes; u32 data = bcm_qspi_read(qspi, BSPI, BSPI_STRAP_OVERRIDE_CTRL); dev_dbg(&qspi->pdev->dev, "set override mode w %x addrlen %x hp %d\n", @@ -437,17 +435,17 @@ static int bcm_qspi_bspi_set_override(struct bcm_qspi *qspi, /* set the override mode */ data |= BSPI_STRAP_OVERRIDE_CTRL_OVERRIDE; bcm_qspi_write(qspi, BSPI, BSPI_STRAP_OVERRIDE_CTRL, data); - bcm_qspi_bspi_set_xfer_params(qspi, msg->read_opcode, 0, 0, 0); + bcm_qspi_bspi_set_xfer_params(qspi, op->cmd.opcode, 0, 0, 0); return 0; } static int bcm_qspi_bspi_set_mode(struct bcm_qspi *qspi, - struct spi_flash_read_message *msg, int hp) + const struct spi_mem_op *op, int hp) { int error = 0; - int width = msg->data_nbits ? msg->data_nbits : SPI_NBITS_SINGLE; - int addrlen = msg->addr_width; + int width = op->data.buswidth ? op->data.buswidth : SPI_NBITS_SINGLE; + int addrlen = op->addr.nbytes; /* default mode */ qspi->xfer_mode.flex_mode = true; @@ -460,12 +458,12 @@ static int bcm_qspi_bspi_set_mode(struct bcm_qspi *qspi, if (val & mask || qspi->s3_strap_override_ctrl & mask) { qspi->xfer_mode.flex_mode = false; bcm_qspi_write(qspi, BSPI, BSPI_FLEX_MODE_ENABLE, 0); - error = bcm_qspi_bspi_set_override(qspi, msg, hp); + error = bcm_qspi_bspi_set_override(qspi, op, hp); } } if (qspi->xfer_mode.flex_mode) - error = bcm_qspi_bspi_set_flex_mode(qspi, msg, hp); + error = bcm_qspi_bspi_set_flex_mode(qspi, op, hp); if (error) { dev_warn(&qspi->pdev->dev, @@ -802,19 +800,20 @@ done: return slot; } -static int bcm_qspi_bspi_flash_read(struct spi_device *spi, - struct spi_flash_read_message *msg) +static int bcm_qspi_bspi_exec_mem_op(struct spi_device *spi, + const struct spi_mem_op *op) { struct bcm_qspi *qspi = spi_master_get_devdata(spi->master); - u32 addr = 0, len, rdlen, len_words; + u32 addr = 0, len, rdlen, len_words, from = 0; int ret = 0; unsigned long timeo = msecs_to_jiffies(100); struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc; if (bcm_qspi_bspi_ver_three(qspi)) - if (msg->addr_width == BSPI_ADDRLEN_4BYTES) + if (op->addr.nbytes == BSPI_ADDRLEN_4BYTES) return -EIO; + from = op->addr.val; bcm_qspi_chip_select(qspi, spi->chip_select); bcm_qspi_write(qspi, MSPI, MSPI_WRITE_LOCK, 0); @@ -823,15 +822,15 @@ static int bcm_qspi_bspi_flash_read(struct spi_device *spi, * the upper address byte to bspi */ if (bcm_qspi_bspi_ver_three(qspi) == false) { - addr = msg->from & 0xff000000; + addr = from & 0xff000000; bcm_qspi_write(qspi, BSPI, BSPI_BSPI_FLASH_UPPER_ADDR_BYTE, addr); } if (!qspi->xfer_mode.flex_mode) - addr = msg->from; + addr = from; else - addr = msg->from & 0x00ffffff; + addr = from & 0x00ffffff; if (bcm_qspi_bspi_ver_three(qspi) == true) addr = (addr + 0xc00000) & 0xffffff; @@ -840,8 +839,8 @@ static int bcm_qspi_bspi_flash_read(struct spi_device *spi, * read into the entire buffer by breaking the reads * into RAF buffer read lengths */ - len = msg->len; - qspi->bspi_rf_msg_idx = 0; + len = op->data.nbytes; + qspi->bspi_rf_op_idx = 0; do { if (len > BSPI_READ_LENGTH) @@ -852,9 +851,9 @@ static int bcm_qspi_bspi_flash_read(struct spi_device *spi, reinit_completion(&qspi->bspi_done); bcm_qspi_enable_bspi(qspi); len_words = (rdlen + 3) >> 2; - qspi->bspi_rf_msg = msg; - qspi->bspi_rf_msg_status = 0; - qspi->bspi_rf_msg_len = rdlen; + qspi->bspi_rf_op = op; + qspi->bspi_rf_op_status = 0; + qspi->bspi_rf_op_len = rdlen; dev_dbg(&qspi->pdev->dev, "bspi xfr addr 0x%x len 0x%x", addr, rdlen); bcm_qspi_write(qspi, BSPI, BSPI_RAF_START_ADDR, addr); @@ -879,7 +878,6 @@ static int bcm_qspi_bspi_flash_read(struct spi_device *spi, } /* set msg return length */ - msg->retlen += rdlen; addr += rdlen; len -= rdlen; } while (len); @@ -914,61 +912,63 @@ static int bcm_qspi_transfer_one(struct spi_master *master, return 0; } -static int bcm_qspi_mspi_flash_read(struct spi_device *spi, - struct spi_flash_read_message *msg) +static int bcm_qspi_mspi_exec_mem_op(struct spi_device *spi, + const struct spi_mem_op *op) { - struct bcm_qspi *qspi = spi_master_get_devdata(spi->master); + struct spi_master *master = spi->master; + struct bcm_qspi *qspi = spi_master_get_devdata(master); struct spi_transfer t[2]; - u8 cmd[6]; - int ret; + u8 cmd[6] = { }; + int ret, i; memset(cmd, 0, sizeof(cmd)); memset(t, 0, sizeof(t)); /* tx */ /* opcode is in cmd[0] */ - cmd[0] = msg->read_opcode; - cmd[1] = msg->from >> (msg->addr_width * 8 - 8); - cmd[2] = msg->from >> (msg->addr_width * 8 - 16); - cmd[3] = msg->from >> (msg->addr_width * 8 - 24); - cmd[4] = msg->from >> (msg->addr_width * 8 - 32); + cmd[0] = op->cmd.opcode; + for (i = 0; i < op->addr.nbytes; i++) + cmd[1 + i] = op->addr.val >> (8 * (op->addr.nbytes - i - 1)); + t[0].tx_buf = cmd; - t[0].len = msg->addr_width + msg->dummy_bytes + 1; + t[0].len = op->addr.nbytes + op->dummy.nbytes + 1; t[0].bits_per_word = spi->bits_per_word; - t[0].tx_nbits = msg->opcode_nbits; + t[0].tx_nbits = op->cmd.buswidth; /* lets mspi know that this is not last transfer */ qspi->trans_pos.mspi_last_trans = false; - ret = bcm_qspi_transfer_one(spi->master, spi, &t[0]); + ret = bcm_qspi_transfer_one(master, spi, &t[0]); /* rx */ qspi->trans_pos.mspi_last_trans = true; if (!ret) { /* rx */ - t[1].rx_buf = msg->buf; - t[1].len = msg->len; - t[1].rx_nbits = msg->data_nbits; + t[1].rx_buf = op->data.buf.in; + t[1].len = op->data.nbytes; + t[1].rx_nbits = op->data.buswidth; t[1].bits_per_word = spi->bits_per_word; - ret = bcm_qspi_transfer_one(spi->master, spi, &t[1]); + ret = bcm_qspi_transfer_one(master, spi, &t[1]); } - if (!ret) - msg->retlen = msg->len; - return ret; } -static int bcm_qspi_flash_read(struct spi_device *spi, - struct spi_flash_read_message *msg) +static int bcm_qspi_exec_mem_op(struct spi_mem *mem, + const struct spi_mem_op *op) { + struct spi_device *spi = mem->spi; struct bcm_qspi *qspi = spi_master_get_devdata(spi->master); int ret = 0; bool mspi_read = false; - u32 addr, len; + u32 addr = 0, len; u_char *buf; - buf = msg->buf; - addr = msg->from; - len = msg->len; + if (!op->data.nbytes || !op->addr.nbytes || op->addr.nbytes > 4 || + op->data.dir != SPI_MEM_DATA_IN) + return -ENOTSUPP; + + buf = op->data.buf.in; + addr = op->addr.val; + len = op->data.nbytes; if (bcm_qspi_bspi_ver_three(qspi) == true) { /* @@ -990,12 +990,12 @@ static int bcm_qspi_flash_read(struct spi_device *spi, mspi_read = true; if (mspi_read) - return bcm_qspi_mspi_flash_read(spi, msg); + return bcm_qspi_mspi_exec_mem_op(spi, op); - ret = bcm_qspi_bspi_set_mode(qspi, msg, -1); + ret = bcm_qspi_bspi_set_mode(qspi, op, -1); if (!ret) - ret = bcm_qspi_bspi_flash_read(spi, msg); + ret = bcm_qspi_bspi_exec_mem_op(spi, op); return ret; } @@ -1034,10 +1034,10 @@ static irqreturn_t bcm_qspi_bspi_lr_l2_isr(int irq, void *dev_id) struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc; u32 status = qspi_dev_id->irqp->mask; - if (qspi->bspi_enabled && qspi->bspi_rf_msg) { + if (qspi->bspi_enabled && qspi->bspi_rf_op) { bcm_qspi_bspi_lr_data_read(qspi); - if (qspi->bspi_rf_msg_len == 0) { - qspi->bspi_rf_msg = NULL; + if (qspi->bspi_rf_op_len == 0) { + qspi->bspi_rf_op = NULL; if (qspi->soc_intc) { /* disable soc BSPI interrupt */ soc_intc->bcm_qspi_int_set(soc_intc, BSPI_DONE, @@ -1046,7 +1046,7 @@ static irqreturn_t bcm_qspi_bspi_lr_l2_isr(int irq, void *dev_id) status = INTR_BSPI_LR_SESSION_DONE_MASK; } - if (qspi->bspi_rf_msg_status) + if (qspi->bspi_rf_op_status) bcm_qspi_bspi_lr_clear(qspi); else bcm_qspi_bspi_flush_prefetch_buffers(qspi); @@ -1058,7 +1058,7 @@ static irqreturn_t bcm_qspi_bspi_lr_l2_isr(int irq, void *dev_id) } status &= INTR_BSPI_LR_SESSION_DONE_MASK; - if (qspi->bspi_enabled && status && qspi->bspi_rf_msg_len == 0) + if (qspi->bspi_enabled && status && qspi->bspi_rf_op_len == 0) complete(&qspi->bspi_done); return IRQ_HANDLED; @@ -1071,7 +1071,7 @@ static irqreturn_t bcm_qspi_bspi_lr_err_l2_isr(int irq, void *dev_id) struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc; dev_err(&qspi->pdev->dev, "BSPI INT error\n"); - qspi->bspi_rf_msg_status = -EIO; + qspi->bspi_rf_op_status = -EIO; if (qspi->soc_intc) /* clear soc interrupt */ soc_intc->bcm_qspi_int_ack(soc_intc, BSPI_ERR); @@ -1194,6 +1194,10 @@ static void bcm_qspi_hw_uninit(struct bcm_qspi *qspi) } +static const struct spi_controller_mem_ops bcm_qspi_mem_ops = { + .exec_op = bcm_qspi_exec_mem_op, +}; + static const struct of_device_id bcm_qspi_of_match[] = { { .compatible = "brcm,spi-bcm-qspi" }, {}, @@ -1236,7 +1240,7 @@ int bcm_qspi_probe(struct platform_device *pdev, master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_RX_DUAL | SPI_RX_QUAD; master->setup = bcm_qspi_setup; master->transfer_one = bcm_qspi_transfer_one; - master->spi_flash_read = bcm_qspi_flash_read; + master->mem_ops = &bcm_qspi_mem_ops; master->cleanup = bcm_qspi_cleanup; master->dev.of_node = dev->of_node; master->num_chipselect = NUM_CHIPSELECT; diff --git a/drivers/spi/spi-bcm53xx.c b/drivers/spi/spi-bcm53xx.c deleted file mode 100644 index d02ceb7a29d1..000000000000 --- a/drivers/spi/spi-bcm53xx.c +++ /dev/null @@ -1,360 +0,0 @@ -/* - * Copyright (C) 2014-2016 RafaĹ‚ MiĹ‚ecki <rafal@milecki.pl> - * - * 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. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/delay.h> -#include <linux/bcma/bcma.h> -#include <linux/spi/spi.h> - -#include "spi-bcm53xx.h" - -#define BCM53XXSPI_MAX_SPI_BAUD 13500000 /* 216 MHz? */ -#define BCM53XXSPI_FLASH_WINDOW SZ_32M - -/* The longest observed required wait was 19 ms */ -#define BCM53XXSPI_SPE_TIMEOUT_MS 80 - -struct bcm53xxspi { - struct bcma_device *core; - struct spi_master *master; - void __iomem *mmio_base; - bool bspi; /* Boot SPI mode with memory mapping */ -}; - -static inline u32 bcm53xxspi_read(struct bcm53xxspi *b53spi, u16 offset) -{ - return bcma_read32(b53spi->core, offset); -} - -static inline void bcm53xxspi_write(struct bcm53xxspi *b53spi, u16 offset, - u32 value) -{ - bcma_write32(b53spi->core, offset, value); -} - -static void bcm53xxspi_disable_bspi(struct bcm53xxspi *b53spi) -{ - struct device *dev = &b53spi->core->dev; - unsigned long deadline; - u32 tmp; - - if (!b53spi->bspi) - return; - - tmp = bcm53xxspi_read(b53spi, B53SPI_BSPI_MAST_N_BOOT_CTRL); - if (tmp & 0x1) - return; - - deadline = jiffies + usecs_to_jiffies(200); - do { - tmp = bcm53xxspi_read(b53spi, B53SPI_BSPI_BUSY_STATUS); - if (!(tmp & 0x1)) { - bcm53xxspi_write(b53spi, B53SPI_BSPI_MAST_N_BOOT_CTRL, - 0x1); - ndelay(200); - b53spi->bspi = false; - return; - } - udelay(1); - } while (!time_after_eq(jiffies, deadline)); - - dev_warn(dev, "Timeout disabling BSPI\n"); -} - -static void bcm53xxspi_enable_bspi(struct bcm53xxspi *b53spi) -{ - u32 tmp; - - if (b53spi->bspi) - return; - - tmp = bcm53xxspi_read(b53spi, B53SPI_BSPI_MAST_N_BOOT_CTRL); - if (!(tmp & 0x1)) - return; - - bcm53xxspi_write(b53spi, B53SPI_BSPI_MAST_N_BOOT_CTRL, 0x0); - b53spi->bspi = true; -} - -static inline unsigned int bcm53xxspi_calc_timeout(size_t len) -{ - /* Do some magic calculation based on length and buad. Add 10% and 1. */ - return (len * 9000 / BCM53XXSPI_MAX_SPI_BAUD * 110 / 100) + 1; -} - -static int bcm53xxspi_wait(struct bcm53xxspi *b53spi, unsigned int timeout_ms) -{ - unsigned long deadline; - u32 tmp; - - /* SPE bit has to be 0 before we read MSPI STATUS */ - deadline = jiffies + msecs_to_jiffies(BCM53XXSPI_SPE_TIMEOUT_MS); - do { - tmp = bcm53xxspi_read(b53spi, B53SPI_MSPI_SPCR2); - if (!(tmp & B53SPI_MSPI_SPCR2_SPE)) - break; - udelay(5); - } while (!time_after_eq(jiffies, deadline)); - - if (tmp & B53SPI_MSPI_SPCR2_SPE) - goto spi_timeout; - - /* Check status */ - deadline = jiffies + msecs_to_jiffies(timeout_ms); - do { - tmp = bcm53xxspi_read(b53spi, B53SPI_MSPI_MSPI_STATUS); - if (tmp & B53SPI_MSPI_MSPI_STATUS_SPIF) { - bcm53xxspi_write(b53spi, B53SPI_MSPI_MSPI_STATUS, 0); - return 0; - } - - cpu_relax(); - udelay(100); - } while (!time_after_eq(jiffies, deadline)); - -spi_timeout: - bcm53xxspi_write(b53spi, B53SPI_MSPI_MSPI_STATUS, 0); - - pr_err("Timeout waiting for SPI to be ready!\n"); - - return -EBUSY; -} - -static void bcm53xxspi_buf_write(struct bcm53xxspi *b53spi, u8 *w_buf, - size_t len, bool cont) -{ - u32 tmp; - int i; - - for (i = 0; i < len; i++) { - /* Transmit Register File MSB */ - bcm53xxspi_write(b53spi, B53SPI_MSPI_TXRAM + 4 * (i * 2), - (unsigned int)w_buf[i]); - } - - for (i = 0; i < len; i++) { - tmp = B53SPI_CDRAM_CONT | B53SPI_CDRAM_PCS_DISABLE_ALL | - B53SPI_CDRAM_PCS_DSCK; - if (!cont && i == len - 1) - tmp &= ~B53SPI_CDRAM_CONT; - tmp &= ~0x1; - /* Command Register File */ - bcm53xxspi_write(b53spi, B53SPI_MSPI_CDRAM + 4 * i, tmp); - } - - /* Set queue pointers */ - bcm53xxspi_write(b53spi, B53SPI_MSPI_NEWQP, 0); - bcm53xxspi_write(b53spi, B53SPI_MSPI_ENDQP, len - 1); - - if (cont) - bcm53xxspi_write(b53spi, B53SPI_MSPI_WRITE_LOCK, 1); - - /* Start SPI transfer */ - tmp = bcm53xxspi_read(b53spi, B53SPI_MSPI_SPCR2); - tmp |= B53SPI_MSPI_SPCR2_SPE; - if (cont) - tmp |= B53SPI_MSPI_SPCR2_CONT_AFTER_CMD; - bcm53xxspi_write(b53spi, B53SPI_MSPI_SPCR2, tmp); - - /* Wait for SPI to finish */ - bcm53xxspi_wait(b53spi, bcm53xxspi_calc_timeout(len)); - - if (!cont) - bcm53xxspi_write(b53spi, B53SPI_MSPI_WRITE_LOCK, 0); -} - -static void bcm53xxspi_buf_read(struct bcm53xxspi *b53spi, u8 *r_buf, - size_t len, bool cont) -{ - u32 tmp; - int i; - - for (i = 0; i < len; i++) { - tmp = B53SPI_CDRAM_CONT | B53SPI_CDRAM_PCS_DISABLE_ALL | - B53SPI_CDRAM_PCS_DSCK; - if (!cont && i == len - 1) - tmp &= ~B53SPI_CDRAM_CONT; - tmp &= ~0x1; - /* Command Register File */ - bcm53xxspi_write(b53spi, B53SPI_MSPI_CDRAM + 4 * i, tmp); - } - - /* Set queue pointers */ - bcm53xxspi_write(b53spi, B53SPI_MSPI_NEWQP, 0); - bcm53xxspi_write(b53spi, B53SPI_MSPI_ENDQP, len - 1); - - if (cont) - bcm53xxspi_write(b53spi, B53SPI_MSPI_WRITE_LOCK, 1); - - /* Start SPI transfer */ - tmp = bcm53xxspi_read(b53spi, B53SPI_MSPI_SPCR2); - tmp |= B53SPI_MSPI_SPCR2_SPE; - if (cont) - tmp |= B53SPI_MSPI_SPCR2_CONT_AFTER_CMD; - bcm53xxspi_write(b53spi, B53SPI_MSPI_SPCR2, tmp); - - /* Wait for SPI to finish */ - bcm53xxspi_wait(b53spi, bcm53xxspi_calc_timeout(len)); - - if (!cont) - bcm53xxspi_write(b53spi, B53SPI_MSPI_WRITE_LOCK, 0); - - for (i = 0; i < len; ++i) { - u16 reg = B53SPI_MSPI_RXRAM + 4 * (1 + i * 2); - - /* Data stored in the transmit register file LSB */ - r_buf[i] = (u8)bcm53xxspi_read(b53spi, reg); - } -} - -static int bcm53xxspi_transfer_one(struct spi_master *master, - struct spi_device *spi, - struct spi_transfer *t) -{ - struct bcm53xxspi *b53spi = spi_master_get_devdata(master); - u8 *buf; - size_t left; - - bcm53xxspi_disable_bspi(b53spi); - - if (t->tx_buf) { - buf = (u8 *)t->tx_buf; - left = t->len; - while (left) { - size_t to_write = min_t(size_t, 16, left); - bool cont = !spi_transfer_is_last(master, t) || - left - to_write > 0; - - bcm53xxspi_buf_write(b53spi, buf, to_write, cont); - left -= to_write; - buf += to_write; - } - } - - if (t->rx_buf) { - buf = (u8 *)t->rx_buf; - left = t->len; - while (left) { - size_t to_read = min_t(size_t, 16, left); - bool cont = !spi_transfer_is_last(master, t) || - left - to_read > 0; - - bcm53xxspi_buf_read(b53spi, buf, to_read, cont); - left -= to_read; - buf += to_read; - } - } - - return 0; -} - -static int bcm53xxspi_flash_read(struct spi_device *spi, - struct spi_flash_read_message *msg) -{ - struct bcm53xxspi *b53spi = spi_master_get_devdata(spi->master); - int ret = 0; - - if (msg->from + msg->len > BCM53XXSPI_FLASH_WINDOW) - return -EINVAL; - - bcm53xxspi_enable_bspi(b53spi); - memcpy_fromio(msg->buf, b53spi->mmio_base + msg->from, msg->len); - msg->retlen = msg->len; - - return ret; -} - -/************************************************** - * BCMA - **************************************************/ - -static const struct bcma_device_id bcm53xxspi_bcma_tbl[] = { - BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_QSPI, BCMA_ANY_REV, BCMA_ANY_CLASS), - {}, -}; -MODULE_DEVICE_TABLE(bcma, bcm53xxspi_bcma_tbl); - -static int bcm53xxspi_bcma_probe(struct bcma_device *core) -{ - struct device *dev = &core->dev; - struct bcm53xxspi *b53spi; - struct spi_master *master; - int err; - - if (core->bus->drv_cc.core->id.rev != 42) { - pr_err("SPI on SoC with unsupported ChipCommon rev\n"); - return -ENOTSUPP; - } - - master = spi_alloc_master(dev, sizeof(*b53spi)); - if (!master) - return -ENOMEM; - - b53spi = spi_master_get_devdata(master); - b53spi->master = master; - b53spi->core = core; - - if (core->addr_s[0]) - b53spi->mmio_base = devm_ioremap(dev, core->addr_s[0], - BCM53XXSPI_FLASH_WINDOW); - b53spi->bspi = true; - bcm53xxspi_disable_bspi(b53spi); - - master->dev.of_node = dev->of_node; - master->transfer_one = bcm53xxspi_transfer_one; - if (b53spi->mmio_base) - master->spi_flash_read = bcm53xxspi_flash_read; - - bcma_set_drvdata(core, b53spi); - - err = devm_spi_register_master(dev, master); - if (err) { - spi_master_put(master); - bcma_set_drvdata(core, NULL); - return err; - } - - return 0; -} - -static struct bcma_driver bcm53xxspi_bcma_driver = { - .name = KBUILD_MODNAME, - .id_table = bcm53xxspi_bcma_tbl, - .probe = bcm53xxspi_bcma_probe, -}; - -/************************************************** - * Init & exit - **************************************************/ - -static int __init bcm53xxspi_module_init(void) -{ - int err = 0; - - err = bcma_driver_register(&bcm53xxspi_bcma_driver); - if (err) - pr_err("Failed to register bcma driver: %d\n", err); - - return err; -} - -static void __exit bcm53xxspi_module_exit(void) -{ - bcma_driver_unregister(&bcm53xxspi_bcma_driver); -} - -module_init(bcm53xxspi_module_init); -module_exit(bcm53xxspi_module_exit); - -MODULE_DESCRIPTION("Broadcom BCM53xx SPI Controller driver"); -MODULE_AUTHOR("RafaĹ‚ MiĹ‚ecki <zajec5@gmail.com>"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/spi/spi-bcm53xx.h b/drivers/spi/spi-bcm53xx.h deleted file mode 100644 index 03e3442086ec..000000000000 --- a/drivers/spi/spi-bcm53xx.h +++ /dev/null @@ -1,73 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef SPI_BCM53XX_H -#define SPI_BCM53XX_H - -#define B53SPI_BSPI_REVISION_ID 0x000 -#define B53SPI_BSPI_SCRATCH 0x004 -#define B53SPI_BSPI_MAST_N_BOOT_CTRL 0x008 -#define B53SPI_BSPI_BUSY_STATUS 0x00c -#define B53SPI_BSPI_INTR_STATUS 0x010 -#define B53SPI_BSPI_B0_STATUS 0x014 -#define B53SPI_BSPI_B0_CTRL 0x018 -#define B53SPI_BSPI_B1_STATUS 0x01c -#define B53SPI_BSPI_B1_CTRL 0x020 -#define B53SPI_BSPI_STRAP_OVERRIDE_CTRL 0x024 -#define B53SPI_BSPI_FLEX_MODE_ENABLE 0x028 -#define B53SPI_BSPI_BITS_PER_CYCLE 0x02c -#define B53SPI_BSPI_BITS_PER_PHASE 0x030 -#define B53SPI_BSPI_CMD_AND_MODE_BYTE 0x034 -#define B53SPI_BSPI_BSPI_FLASH_UPPER_ADDR_BYTE 0x038 -#define B53SPI_BSPI_BSPI_XOR_VALUE 0x03c -#define B53SPI_BSPI_BSPI_XOR_ENABLE 0x040 -#define B53SPI_BSPI_BSPI_PIO_MODE_ENABLE 0x044 -#define B53SPI_BSPI_BSPI_PIO_IODIR 0x048 -#define B53SPI_BSPI_BSPI_PIO_DATA 0x04c - -/* RAF */ -#define B53SPI_RAF_START_ADDR 0x100 -#define B53SPI_RAF_NUM_WORDS 0x104 -#define B53SPI_RAF_CTRL 0x108 -#define B53SPI_RAF_FULLNESS 0x10c -#define B53SPI_RAF_WATERMARK 0x110 -#define B53SPI_RAF_STATUS 0x114 -#define B53SPI_RAF_READ_DATA 0x118 -#define B53SPI_RAF_WORD_CNT 0x11c -#define B53SPI_RAF_CURR_ADDR 0x120 - -/* MSPI */ -#define B53SPI_MSPI_SPCR0_LSB 0x200 -#define B53SPI_MSPI_SPCR0_MSB 0x204 -#define B53SPI_MSPI_SPCR1_LSB 0x208 -#define B53SPI_MSPI_SPCR1_MSB 0x20c -#define B53SPI_MSPI_NEWQP 0x210 -#define B53SPI_MSPI_ENDQP 0x214 -#define B53SPI_MSPI_SPCR2 0x218 -#define B53SPI_MSPI_SPCR2_SPE 0x00000040 -#define B53SPI_MSPI_SPCR2_CONT_AFTER_CMD 0x00000080 -#define B53SPI_MSPI_MSPI_STATUS 0x220 -#define B53SPI_MSPI_MSPI_STATUS_SPIF 0x00000001 -#define B53SPI_MSPI_CPTQP 0x224 -#define B53SPI_MSPI_TXRAM 0x240 /* 32 registers, up to 0x2b8 */ -#define B53SPI_MSPI_RXRAM 0x2c0 /* 32 registers, up to 0x33c */ -#define B53SPI_MSPI_CDRAM 0x340 /* 16 registers, up to 0x37c */ -#define B53SPI_CDRAM_PCS_PCS0 0x00000001 -#define B53SPI_CDRAM_PCS_PCS1 0x00000002 -#define B53SPI_CDRAM_PCS_PCS2 0x00000004 -#define B53SPI_CDRAM_PCS_PCS3 0x00000008 -#define B53SPI_CDRAM_PCS_DISABLE_ALL 0x0000000f -#define B53SPI_CDRAM_PCS_DSCK 0x00000010 -#define B53SPI_CDRAM_BITSE 0x00000040 -#define B53SPI_CDRAM_CONT 0x00000080 -#define B53SPI_MSPI_WRITE_LOCK 0x380 -#define B53SPI_MSPI_DISABLE_FLUSH_GEN 0x384 - -/* Interrupt */ -#define B53SPI_INTR_RAF_LR_FULLNESS_REACHED 0x3a0 -#define B53SPI_INTR_RAF_LR_TRUNCATED 0x3a4 -#define B53SPI_INTR_RAF_LR_IMPATIENT 0x3a8 -#define B53SPI_INTR_RAF_LR_SESSION_DONE 0x3ac -#define B53SPI_INTR_RAF_LR_OVERREAD 0x3b0 -#define B53SPI_INTR_MSPI_DONE 0x3b4 -#define B53SPI_INTR_MSPI_HALT_SET_TRANSACTION_DONE 0x3b8 - -#endif /* SPI_BCM53XX_H */ diff --git a/drivers/spi/spi-bcm63xx-hsspi.c b/drivers/spi/spi-bcm63xx-hsspi.c index cbcba614b253..c23849f7aa7b 100644 --- a/drivers/spi/spi-bcm63xx-hsspi.c +++ b/drivers/spi/spi-bcm63xx-hsspi.c @@ -352,22 +352,31 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev) if (IS_ERR(clk)) return PTR_ERR(clk); + ret = clk_prepare_enable(clk); + if (ret) + return ret; + rate = clk_get_rate(clk); if (!rate) { struct clk *pll_clk = devm_clk_get(dev, "pll"); - if (IS_ERR(pll_clk)) - return PTR_ERR(pll_clk); + if (IS_ERR(pll_clk)) { + ret = PTR_ERR(pll_clk); + goto out_disable_clk; + } + + ret = clk_prepare_enable(pll_clk); + if (ret) + goto out_disable_clk; rate = clk_get_rate(pll_clk); - if (!rate) - return -EINVAL; + clk_disable_unprepare(pll_clk); + if (!rate) { + ret = -EINVAL; + goto out_disable_clk; + } } - ret = clk_prepare_enable(clk); - if (ret) - return ret; - master = spi_alloc_master(&pdev->dev, sizeof(*bs)); if (!master) { ret = -ENOMEM; diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c index 4a001634023e..f3dad6fcdc35 100644 --- a/drivers/spi/spi-cadence.c +++ b/drivers/spi/spi-cadence.c @@ -694,8 +694,7 @@ static int cdns_spi_remove(struct platform_device *pdev) */ static int __maybe_unused cdns_spi_suspend(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct spi_master *master = platform_get_drvdata(pdev); + struct spi_master *master = dev_get_drvdata(dev); return spi_master_suspend(master); } @@ -710,8 +709,7 @@ static int __maybe_unused cdns_spi_suspend(struct device *dev) */ static int __maybe_unused cdns_spi_resume(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct spi_master *master = platform_get_drvdata(pdev); + struct spi_master *master = dev_get_drvdata(dev); struct cdns_spi *xspi = spi_master_get_devdata(master); cdns_spi_init_hw(xspi); diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index cb3c73007ca1..e6d5cc6ab108 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -1,19 +1,8 @@ -/* - * Freescale i.MX7ULP LPSPI driver - * - * Copyright 2016 Freescale Semiconductor, Inc. - * - * 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; either version 2 of the License, or - * (at your option) any later version. - * - * 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. - * - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// Freescale i.MX7ULP LPSPI driver +// +// Copyright 2016 Freescale Semiconductor, Inc. #include <linux/clk.h> #include <linux/completion.h> diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index a056ee88a960..866246f21041 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -1,22 +1,6 @@ -/* - * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. - * Copyright (C) 2008 Juergen Beisert - * - * 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; either version 2 - * of the License, or (at your option) any later version. - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation - * 51 Franklin Street, Fifth Floor - * Boston, MA 02110-1301, USA. - */ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. +// Copyright (C) 2008 Juergen Beisert #include <linux/clk.h> #include <linux/completion.h> diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c new file mode 100644 index 000000000000..990770dfa5cf --- /dev/null +++ b/drivers/spi/spi-mem.c @@ -0,0 +1,410 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018 Exceet Electronics GmbH + * Copyright (C) 2018 Bootlin + * + * Author: Boris Brezillon <boris.brezillon@bootlin.com> + */ +#include <linux/dmaengine.h> +#include <linux/pm_runtime.h> +#include <linux/spi/spi.h> +#include <linux/spi/spi-mem.h> + +#include "internals.h" + +/** + * spi_controller_dma_map_mem_op_data() - DMA-map the buffer attached to a + * memory operation + * @ctlr: the SPI controller requesting this dma_map() + * @op: the memory operation containing the buffer to map + * @sgt: a pointer to a non-initialized sg_table that will be filled by this + * function + * + * Some controllers might want to do DMA on the data buffer embedded in @op. + * This helper prepares everything for you and provides a ready-to-use + * sg_table. This function is not intended to be called from spi drivers. + * Only SPI controller drivers should use it. + * Note that the caller must ensure the memory region pointed by + * op->data.buf.{in,out} is DMA-able before calling this function. + * + * Return: 0 in case of success, a negative error code otherwise. + */ +int spi_controller_dma_map_mem_op_data(struct spi_controller *ctlr, + const struct spi_mem_op *op, + struct sg_table *sgt) +{ + struct device *dmadev; + + if (!op->data.nbytes) + return -EINVAL; + + if (op->data.dir == SPI_MEM_DATA_OUT && ctlr->dma_tx) + dmadev = ctlr->dma_tx->device->dev; + else if (op->data.dir == SPI_MEM_DATA_IN && ctlr->dma_rx) + dmadev = ctlr->dma_rx->device->dev; + else + dmadev = ctlr->dev.parent; + + if (!dmadev) + return -EINVAL; + + return spi_map_buf(ctlr, dmadev, sgt, op->data.buf.in, op->data.nbytes, + op->data.dir == SPI_MEM_DATA_IN ? + DMA_FROM_DEVICE : DMA_TO_DEVICE); +} +EXPORT_SYMBOL_GPL(spi_controller_dma_map_mem_op_data); + +/** + * spi_controller_dma_unmap_mem_op_data() - DMA-unmap the buffer attached to a + * memory operation + * @ctlr: the SPI controller requesting this dma_unmap() + * @op: the memory operation containing the buffer to unmap + * @sgt: a pointer to an sg_table previously initialized by + * spi_controller_dma_map_mem_op_data() + * + * Some controllers might want to do DMA on the data buffer embedded in @op. + * This helper prepares things so that the CPU can access the + * op->data.buf.{in,out} buffer again. + * + * This function is not intended to be called from SPI drivers. Only SPI + * controller drivers should use it. + * + * This function should be called after the DMA operation has finished and is + * only valid if the previous spi_controller_dma_map_mem_op_data() call + * returned 0. + * + * Return: 0 in case of success, a negative error code otherwise. + */ +void spi_controller_dma_unmap_mem_op_data(struct spi_controller *ctlr, + const struct spi_mem_op *op, + struct sg_table *sgt) +{ + struct device *dmadev; + + if (!op->data.nbytes) + return; + + if (op->data.dir == SPI_MEM_DATA_OUT && ctlr->dma_tx) + dmadev = ctlr->dma_tx->device->dev; + else if (op->data.dir == SPI_MEM_DATA_IN && ctlr->dma_rx) + dmadev = ctlr->dma_rx->device->dev; + else + dmadev = ctlr->dev.parent; + + spi_unmap_buf(ctlr, dmadev, sgt, + op->data.dir == SPI_MEM_DATA_IN ? + DMA_FROM_DEVICE : DMA_TO_DEVICE); +} +EXPORT_SYMBOL_GPL(spi_controller_dma_unmap_mem_op_data); + +static int spi_check_buswidth_req(struct spi_mem *mem, u8 buswidth, bool tx) +{ + u32 mode = mem->spi->mode; + + switch (buswidth) { + case 1: + return 0; + + case 2: + if ((tx && (mode & (SPI_TX_DUAL | SPI_TX_QUAD))) || + (!tx && (mode & (SPI_RX_DUAL | SPI_RX_QUAD)))) + return 0; + + break; + + case 4: + if ((tx && (mode & SPI_TX_QUAD)) || + (!tx && (mode & SPI_RX_QUAD))) + return 0; + + break; + + default: + break; + } + + return -ENOTSUPP; +} + +static bool spi_mem_default_supports_op(struct spi_mem *mem, + const struct spi_mem_op *op) +{ + if (spi_check_buswidth_req(mem, op->cmd.buswidth, true)) + return false; + + if (op->addr.nbytes && + spi_check_buswidth_req(mem, op->addr.buswidth, true)) + return false; + + if (op->dummy.nbytes && + spi_check_buswidth_req(mem, op->dummy.buswidth, true)) + return false; + + if (op->data.nbytes && + spi_check_buswidth_req(mem, op->data.buswidth, + op->data.dir == SPI_MEM_DATA_OUT)) + return false; + + return true; +} +EXPORT_SYMBOL_GPL(spi_mem_default_supports_op); + +/** + * spi_mem_supports_op() - Check if a memory device and the controller it is + * connected to support a specific memory operation + * @mem: the SPI memory + * @op: the memory operation to check + * + * Some controllers are only supporting Single or Dual IOs, others might only + * support specific opcodes, or it can even be that the controller and device + * both support Quad IOs but the hardware prevents you from using it because + * only 2 IO lines are connected. + * + * This function checks whether a specific operation is supported. + * + * Return: true if @op is supported, false otherwise. + */ +bool spi_mem_supports_op(struct spi_mem *mem, const struct spi_mem_op *op) +{ + struct spi_controller *ctlr = mem->spi->controller; + + if (ctlr->mem_ops && ctlr->mem_ops->supports_op) + return ctlr->mem_ops->supports_op(mem, op); + + return spi_mem_default_supports_op(mem, op); +} +EXPORT_SYMBOL_GPL(spi_mem_supports_op); + +/** + * spi_mem_exec_op() - Execute a memory operation + * @mem: the SPI memory + * @op: the memory operation to execute + * + * Executes a memory operation. + * + * This function first checks that @op is supported and then tries to execute + * it. + * + * Return: 0 in case of success, a negative error code otherwise. + */ +int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) +{ + unsigned int tmpbufsize, xferpos = 0, totalxferlen = 0; + struct spi_controller *ctlr = mem->spi->controller; + struct spi_transfer xfers[4] = { }; + struct spi_message msg; + u8 *tmpbuf; + int ret; + + if (!spi_mem_supports_op(mem, op)) + return -ENOTSUPP; + + if (ctlr->mem_ops) { + /* + * Flush the message queue before executing our SPI memory + * operation to prevent preemption of regular SPI transfers. + */ + spi_flush_queue(ctlr); + + if (ctlr->auto_runtime_pm) { + ret = pm_runtime_get_sync(ctlr->dev.parent); + if (ret < 0) { + dev_err(&ctlr->dev, + "Failed to power device: %d\n", + ret); + return ret; + } + } + + mutex_lock(&ctlr->bus_lock_mutex); + mutex_lock(&ctlr->io_mutex); + ret = ctlr->mem_ops->exec_op(mem, op); + mutex_unlock(&ctlr->io_mutex); + mutex_unlock(&ctlr->bus_lock_mutex); + + if (ctlr->auto_runtime_pm) + pm_runtime_put(ctlr->dev.parent); + + /* + * Some controllers only optimize specific paths (typically the + * read path) and expect the core to use the regular SPI + * interface in other cases. + */ + if (!ret || ret != -ENOTSUPP) + return ret; + } + + tmpbufsize = sizeof(op->cmd.opcode) + op->addr.nbytes + + op->dummy.nbytes; + + /* + * Allocate a buffer to transmit the CMD, ADDR cycles with kmalloc() so + * we're guaranteed that this buffer is DMA-able, as required by the + * SPI layer. + */ + tmpbuf = kzalloc(tmpbufsize, GFP_KERNEL | GFP_DMA); + if (!tmpbuf) + return -ENOMEM; + + spi_message_init(&msg); + + tmpbuf[0] = op->cmd.opcode; + xfers[xferpos].tx_buf = tmpbuf; + xfers[xferpos].len = sizeof(op->cmd.opcode); + xfers[xferpos].tx_nbits = op->cmd.buswidth; + spi_message_add_tail(&xfers[xferpos], &msg); + xferpos++; + totalxferlen++; + + if (op->addr.nbytes) { + int i; + + for (i = 0; i < op->addr.nbytes; i++) + tmpbuf[i + 1] = op->addr.val >> + (8 * (op->addr.nbytes - i - 1)); + + xfers[xferpos].tx_buf = tmpbuf + 1; + xfers[xferpos].len = op->addr.nbytes; + xfers[xferpos].tx_nbits = op->addr.buswidth; + spi_message_add_tail(&xfers[xferpos], &msg); + xferpos++; + totalxferlen += op->addr.nbytes; + } + + if (op->dummy.nbytes) { + memset(tmpbuf + op->addr.nbytes + 1, 0xff, op->dummy.nbytes); + xfers[xferpos].tx_buf = tmpbuf + op->addr.nbytes + 1; + xfers[xferpos].len = op->dummy.nbytes; + xfers[xferpos].tx_nbits = op->dummy.buswidth; + spi_message_add_tail(&xfers[xferpos], &msg); + xferpos++; + totalxferlen += op->dummy.nbytes; + } + + if (op->data.nbytes) { + if (op->data.dir == SPI_MEM_DATA_IN) { + xfers[xferpos].rx_buf = op->data.buf.in; + xfers[xferpos].rx_nbits = op->data.buswidth; + } else { + xfers[xferpos].tx_buf = op->data.buf.out; + xfers[xferpos].tx_nbits = op->data.buswidth; + } + + xfers[xferpos].len = op->data.nbytes; + spi_message_add_tail(&xfers[xferpos], &msg); + xferpos++; + totalxferlen += op->data.nbytes; + } + + ret = spi_sync(mem->spi, &msg); + + kfree(tmpbuf); + + if (ret) + return ret; + + if (msg.actual_length != totalxferlen) + return -EIO; + + return 0; +} +EXPORT_SYMBOL_GPL(spi_mem_exec_op); + +/** + * spi_mem_adjust_op_size() - Adjust the data size of a SPI mem operation to + * match controller limitations + * @mem: the SPI memory + * @op: the operation to adjust + * + * Some controllers have FIFO limitations and must split a data transfer + * operation into multiple ones, others require a specific alignment for + * optimized accesses. This function allows SPI mem drivers to split a single + * operation into multiple sub-operations when required. + * + * Return: a negative error code if the controller can't properly adjust @op, + * 0 otherwise. Note that @op->data.nbytes will be updated if @op + * can't be handled in a single step. + */ +int spi_mem_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op) +{ + struct spi_controller *ctlr = mem->spi->controller; + + if (ctlr->mem_ops && ctlr->mem_ops->adjust_op_size) + return ctlr->mem_ops->adjust_op_size(mem, op); + + return 0; +} +EXPORT_SYMBOL_GPL(spi_mem_adjust_op_size); + +static inline struct spi_mem_driver *to_spi_mem_drv(struct device_driver *drv) +{ + return container_of(drv, struct spi_mem_driver, spidrv.driver); +} + +static int spi_mem_probe(struct spi_device *spi) +{ + struct spi_mem_driver *memdrv = to_spi_mem_drv(spi->dev.driver); + struct spi_mem *mem; + + mem = devm_kzalloc(&spi->dev, sizeof(*mem), GFP_KERNEL); + if (!mem) + return -ENOMEM; + + mem->spi = spi; + spi_set_drvdata(spi, mem); + + return memdrv->probe(mem); +} + +static int spi_mem_remove(struct spi_device *spi) +{ + struct spi_mem_driver *memdrv = to_spi_mem_drv(spi->dev.driver); + struct spi_mem *mem = spi_get_drvdata(spi); + + if (memdrv->remove) + return memdrv->remove(mem); + + return 0; +} + +static void spi_mem_shutdown(struct spi_device *spi) +{ + struct spi_mem_driver *memdrv = to_spi_mem_drv(spi->dev.driver); + struct spi_mem *mem = spi_get_drvdata(spi); + + if (memdrv->shutdown) + memdrv->shutdown(mem); +} + +/** + * spi_mem_driver_register_with_owner() - Register a SPI memory driver + * @memdrv: the SPI memory driver to register + * @owner: the owner of this driver + * + * Registers a SPI memory driver. + * + * Return: 0 in case of success, a negative error core otherwise. + */ + +int spi_mem_driver_register_with_owner(struct spi_mem_driver *memdrv, + struct module *owner) +{ + memdrv->spidrv.probe = spi_mem_probe; + memdrv->spidrv.remove = spi_mem_remove; + memdrv->spidrv.shutdown = spi_mem_shutdown; + + return __spi_register_driver(owner, &memdrv->spidrv); +} +EXPORT_SYMBOL_GPL(spi_mem_driver_register_with_owner); + +/** + * spi_mem_driver_unregister_with_owner() - Unregister a SPI memory driver + * @memdrv: the SPI memory driver to unregister + * + * Unregisters a SPI memory driver. + */ +void spi_mem_driver_unregister(struct spi_mem_driver *memdrv) +{ + spi_unregister_driver(&memdrv->spidrv); +} +EXPORT_SYMBOL_GPL(spi_mem_driver_unregister); diff --git a/drivers/spi/spi-meson-spicc.c b/drivers/spi/spi-meson-spicc.c index 5c82910e3480..7fe4488ace57 100644 --- a/drivers/spi/spi-meson-spicc.c +++ b/drivers/spi/spi-meson-spicc.c @@ -574,10 +574,15 @@ static int meson_spicc_probe(struct platform_device *pdev) master->max_speed_hz = rate >> 2; ret = devm_spi_register_master(&pdev->dev, master); - if (!ret) - return 0; + if (ret) { + dev_err(&pdev->dev, "spi master registration failed\n"); + goto out_clk; + } - dev_err(&pdev->dev, "spi master registration failed\n"); + return 0; + +out_clk: + clk_disable_unprepare(spicc->core); out_master: spi_master_put(master); diff --git a/drivers/spi/spi-mpc52xx.c b/drivers/spi/spi-mpc52xx.c index e8b59ce4dc3a..0e55784a3ad9 100644 --- a/drivers/spi/spi-mpc52xx.c +++ b/drivers/spi/spi-mpc52xx.c @@ -447,7 +447,7 @@ static int mpc52xx_spi_probe(struct platform_device *op) for (i = 0; i < ms->gpio_cs_count; i++) { gpio_cs = of_get_gpio(op->dev.of_node, i); - if (gpio_cs < 0) { + if (!gpio_is_valid(gpio_cs)) { dev_err(&op->dev, "could not parse the gpio field in oftree\n"); rc = -ENODEV; diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c index 3d216b950b41..6ac95a2a21ce 100644 --- a/drivers/spi/spi-mxs.c +++ b/drivers/spi/spi-mxs.c @@ -1,32 +1,22 @@ -/* - * Freescale MXS SPI master driver - * - * Copyright 2012 DENX Software Engineering, GmbH. - * Copyright 2012 Freescale Semiconductor, Inc. - * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. - * - * Rework and transition to new API by: - * Marek Vasut <marex@denx.de> - * - * Based on previous attempt by: - * Fabio Estevam <fabio.estevam@freescale.com> - * - * Based on code from U-Boot bootloader by: - * Marek Vasut <marex@denx.de> - * - * Based on spi-stmp.c, which is: - * Author: Dmitry Pervushin <dimka@embeddedalley.com> - * - * 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; either version 2 of the License, or - * (at your option) any later version. - * - * 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. - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// Freescale MXS SPI master driver +// +// Copyright 2012 DENX Software Engineering, GmbH. +// Copyright 2012 Freescale Semiconductor, Inc. +// Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. +// +// Rework and transition to new API by: +// Marek Vasut <marex@denx.de> +// +// Based on previous attempt by: +// Fabio Estevam <fabio.estevam@freescale.com> +// +// Based on code from U-Boot bootloader by: +// Marek Vasut <marex@denx.de> +// +// Based on spi-stmp.c, which is: +// Author: Dmitry Pervushin <dimka@embeddedalley.com> #include <linux/kernel.h> #include <linux/ioport.h> diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 9bf64e6eca9b..6c628a54e946 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -255,6 +255,7 @@ static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable) if (spi->controller_state) { int err = pm_runtime_get_sync(mcspi->dev); if (err < 0) { + pm_runtime_put_noidle(mcspi->dev); dev_err(mcspi->dev, "failed to get sync: %d\n", err); return; } @@ -350,20 +351,6 @@ disable_fifo: mcspi->fifo_depth = 0; } -static void omap2_mcspi_restore_ctx(struct omap2_mcspi *mcspi) -{ - struct spi_master *spi_cntrl = mcspi->master; - struct omap2_mcspi_regs *ctx = &mcspi->ctx; - struct omap2_mcspi_cs *cs; - - /* McSPI: context restore */ - mcspi_write_reg(spi_cntrl, OMAP2_MCSPI_MODULCTRL, ctx->modulctrl); - mcspi_write_reg(spi_cntrl, OMAP2_MCSPI_WAKEUPENABLE, ctx->wakeupenable); - - list_for_each_entry(cs, &ctx->cs, node) - writel_relaxed(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0); -} - static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit) { unsigned long timeout; @@ -1065,8 +1052,11 @@ static int omap2_mcspi_setup(struct spi_device *spi) } ret = pm_runtime_get_sync(mcspi->dev); - if (ret < 0) + if (ret < 0) { + pm_runtime_put_noidle(mcspi->dev); + return ret; + } ret = omap2_mcspi_setup_transfer(spi, NULL); pm_runtime_mark_last_busy(mcspi->dev); @@ -1284,8 +1274,11 @@ static int omap2_mcspi_master_setup(struct omap2_mcspi *mcspi) int ret = 0; ret = pm_runtime_get_sync(mcspi->dev); - if (ret < 0) + if (ret < 0) { + pm_runtime_put_noidle(mcspi->dev); + return ret; + } mcspi_write_reg(master, OMAP2_MCSPI_WAKEUPENABLE, OMAP2_MCSPI_WAKEUPENABLE_WKEN); @@ -1297,14 +1290,39 @@ static int omap2_mcspi_master_setup(struct omap2_mcspi *mcspi) return 0; } +/* + * When SPI wake up from off-mode, CS is in activate state. If it was in + * inactive state when driver was suspend, then force it to inactive state at + * wake up. + */ static int omap_mcspi_runtime_resume(struct device *dev) { - struct omap2_mcspi *mcspi; - struct spi_master *master; + struct spi_master *master = dev_get_drvdata(dev); + struct omap2_mcspi *mcspi = spi_master_get_devdata(master); + struct omap2_mcspi_regs *ctx = &mcspi->ctx; + struct omap2_mcspi_cs *cs; - master = dev_get_drvdata(dev); - mcspi = spi_master_get_devdata(master); - omap2_mcspi_restore_ctx(mcspi); + /* McSPI: context restore */ + mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, ctx->modulctrl); + mcspi_write_reg(master, OMAP2_MCSPI_WAKEUPENABLE, ctx->wakeupenable); + + list_for_each_entry(cs, &ctx->cs, node) { + /* + * We need to toggle CS state for OMAP take this + * change in account. + */ + if ((cs->chconf0 & OMAP2_MCSPI_CHCONF_FORCE) == 0) { + cs->chconf0 |= OMAP2_MCSPI_CHCONF_FORCE; + writel_relaxed(cs->chconf0, + cs->base + OMAP2_MCSPI_CHCONF0); + cs->chconf0 &= ~OMAP2_MCSPI_CHCONF_FORCE; + writel_relaxed(cs->chconf0, + cs->base + OMAP2_MCSPI_CHCONF0); + } else { + writel_relaxed(cs->chconf0, + cs->base + OMAP2_MCSPI_CHCONF0); + } + } return 0; } @@ -1447,50 +1465,33 @@ static int omap2_mcspi_remove(struct platform_device *pdev) MODULE_ALIAS("platform:omap2_mcspi"); #ifdef CONFIG_SUSPEND -/* - * When SPI wake up from off-mode, CS is in activate state. If it was in - * unactive state when driver was suspend, then force it to unactive state at - * wake up. - */ -static int omap2_mcspi_resume(struct device *dev) +static int omap2_mcspi_suspend_noirq(struct device *dev) { - struct spi_master *master = dev_get_drvdata(dev); - struct omap2_mcspi *mcspi = spi_master_get_devdata(master); - struct omap2_mcspi_regs *ctx = &mcspi->ctx; - struct omap2_mcspi_cs *cs; - - pm_runtime_get_sync(mcspi->dev); - list_for_each_entry(cs, &ctx->cs, node) { - if ((cs->chconf0 & OMAP2_MCSPI_CHCONF_FORCE) == 0) { - /* - * We need to toggle CS state for OMAP take this - * change in account. - */ - cs->chconf0 |= OMAP2_MCSPI_CHCONF_FORCE; - writel_relaxed(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0); - cs->chconf0 &= ~OMAP2_MCSPI_CHCONF_FORCE; - writel_relaxed(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0); - } - } - pm_runtime_mark_last_busy(mcspi->dev); - pm_runtime_put_autosuspend(mcspi->dev); - - return pinctrl_pm_select_default_state(dev); + return pinctrl_pm_select_sleep_state(dev); } -static int omap2_mcspi_suspend(struct device *dev) +static int omap2_mcspi_resume_noirq(struct device *dev) { - return pinctrl_pm_select_sleep_state(dev); + struct spi_master *master = dev_get_drvdata(dev); + struct omap2_mcspi *mcspi = spi_master_get_devdata(master); + int error; + + error = pinctrl_pm_select_default_state(dev); + if (error) + dev_warn(mcspi->dev, "%s: failed to set pins: %i\n", + __func__, error); + + return 0; } #else -#define omap2_mcspi_suspend NULL -#define omap2_mcspi_resume NULL +#define omap2_mcspi_suspend_noirq NULL +#define omap2_mcspi_resume_noirq NULL #endif static const struct dev_pm_ops omap2_mcspi_pm_ops = { - .resume = omap2_mcspi_resume, - .suspend = omap2_mcspi_suspend, + .suspend_noirq = omap2_mcspi_suspend_noirq, + .resume_noirq = omap2_mcspi_resume_noirq, .runtime_resume = omap_mcspi_runtime_resume, }; diff --git a/drivers/spi/spi-pxa2xx-dma.c b/drivers/spi/spi-pxa2xx-dma.c index 3d7f66080c57..2fa7f4b43492 100644 --- a/drivers/spi/spi-pxa2xx-dma.c +++ b/drivers/spi/spi-pxa2xx-dma.c @@ -51,19 +51,15 @@ static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data, if (!pxa25x_ssp_comp(drv_data)) pxa2xx_spi_write(drv_data, SSTO, 0); - if (!error) { - msg->actual_length += drv_data->len; - msg->state = pxa2xx_spi_next_transfer(drv_data); - } else { + if (error) { /* In case we got an error we disable the SSP now */ pxa2xx_spi_write(drv_data, SSCR0, pxa2xx_spi_read(drv_data, SSCR0) & ~SSCR0_SSE); - - msg->state = ERROR_STATE; + msg->status = -EIO; } - tasklet_schedule(&drv_data->pump_transfers); + spi_finalize_current_transfer(drv_data->master); } } @@ -74,11 +70,11 @@ static void pxa2xx_spi_dma_callback(void *data) static struct dma_async_tx_descriptor * pxa2xx_spi_dma_prepare_one(struct driver_data *drv_data, - enum dma_transfer_direction dir) + enum dma_transfer_direction dir, + struct spi_transfer *xfer) { struct chip_data *chip = spi_get_ctldata(drv_data->master->cur_msg->spi); - struct spi_transfer *xfer = drv_data->cur_transfer; enum dma_slave_buswidth width; struct dma_slave_config cfg; struct dma_chan *chan; @@ -144,12 +140,13 @@ irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data) return IRQ_NONE; } -int pxa2xx_spi_dma_prepare(struct driver_data *drv_data, u32 dma_burst) +int pxa2xx_spi_dma_prepare(struct driver_data *drv_data, + struct spi_transfer *xfer) { struct dma_async_tx_descriptor *tx_desc, *rx_desc; int err; - tx_desc = pxa2xx_spi_dma_prepare_one(drv_data, DMA_MEM_TO_DEV); + tx_desc = pxa2xx_spi_dma_prepare_one(drv_data, DMA_MEM_TO_DEV, xfer); if (!tx_desc) { dev_err(&drv_data->pdev->dev, "failed to get DMA TX descriptor\n"); @@ -157,7 +154,7 @@ int pxa2xx_spi_dma_prepare(struct driver_data *drv_data, u32 dma_burst) goto err_tx; } - rx_desc = pxa2xx_spi_dma_prepare_one(drv_data, DMA_DEV_TO_MEM); + rx_desc = pxa2xx_spi_dma_prepare_one(drv_data, DMA_DEV_TO_MEM, xfer); if (!rx_desc) { dev_err(&drv_data->pdev->dev, "failed to get DMA RX descriptor\n"); @@ -187,6 +184,13 @@ void pxa2xx_spi_dma_start(struct driver_data *drv_data) atomic_set(&drv_data->dma_running, 1); } +void pxa2xx_spi_dma_stop(struct driver_data *drv_data) +{ + atomic_set(&drv_data->dma_running, 0); + dmaengine_terminate_sync(drv_data->master->dma_rx); + dmaengine_terminate_sync(drv_data->master->dma_tx); +} + int pxa2xx_spi_dma_setup(struct driver_data *drv_data) { struct pxa2xx_spi_master *pdata = drv_data->master_info; diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 82dcb88fcfba..0b2d60d30f69 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -340,9 +340,11 @@ static void lpss_ssp_setup(struct driver_data *drv_data) } } -static void lpss_ssp_select_cs(struct driver_data *drv_data, +static void lpss_ssp_select_cs(struct spi_device *spi, const struct lpss_config *config) { + struct driver_data *drv_data = + spi_controller_get_devdata(spi->controller); u32 value, cs; if (!config->cs_sel_mask) @@ -350,7 +352,7 @@ static void lpss_ssp_select_cs(struct driver_data *drv_data, value = __lpss_ssp_read_priv(drv_data, config->reg_cs_ctrl); - cs = drv_data->master->cur_msg->spi->chip_select; + cs = spi->chip_select; cs <<= config->cs_sel_shift; if (cs != (value & config->cs_sel_mask)) { /* @@ -369,15 +371,17 @@ static void lpss_ssp_select_cs(struct driver_data *drv_data, } } -static void lpss_ssp_cs_control(struct driver_data *drv_data, bool enable) +static void lpss_ssp_cs_control(struct spi_device *spi, bool enable) { + struct driver_data *drv_data = + spi_controller_get_devdata(spi->controller); const struct lpss_config *config; u32 value; config = lpss_get_config(drv_data); if (enable) - lpss_ssp_select_cs(drv_data, config); + lpss_ssp_select_cs(spi, config); value = __lpss_ssp_read_priv(drv_data, config->reg_cs_ctrl); if (enable) @@ -387,10 +391,11 @@ static void lpss_ssp_cs_control(struct driver_data *drv_data, bool enable) __lpss_ssp_write_priv(drv_data, config->reg_cs_ctrl, value); } -static void cs_assert(struct driver_data *drv_data) +static void cs_assert(struct spi_device *spi) { - struct chip_data *chip = - spi_get_ctldata(drv_data->master->cur_msg->spi); + struct chip_data *chip = spi_get_ctldata(spi); + struct driver_data *drv_data = + spi_controller_get_devdata(spi->controller); if (drv_data->ssp_type == CE4100_SSP) { pxa2xx_spi_write(drv_data, SSSR, chip->frm); @@ -408,13 +413,14 @@ static void cs_assert(struct driver_data *drv_data) } if (is_lpss_ssp(drv_data)) - lpss_ssp_cs_control(drv_data, true); + lpss_ssp_cs_control(spi, true); } -static void cs_deassert(struct driver_data *drv_data) +static void cs_deassert(struct spi_device *spi) { - struct chip_data *chip = - spi_get_ctldata(drv_data->master->cur_msg->spi); + struct chip_data *chip = spi_get_ctldata(spi); + struct driver_data *drv_data = + spi_controller_get_devdata(spi->controller); unsigned long timeout; if (drv_data->ssp_type == CE4100_SSP) @@ -437,7 +443,15 @@ static void cs_deassert(struct driver_data *drv_data) } if (is_lpss_ssp(drv_data)) - lpss_ssp_cs_control(drv_data, false); + lpss_ssp_cs_control(spi, false); +} + +static void pxa2xx_spi_set_cs(struct spi_device *spi, bool level) +{ + if (level) + cs_deassert(spi); + else + cs_assert(spi); } int pxa2xx_spi_flush(struct driver_data *drv_data) @@ -549,70 +563,6 @@ static int u32_reader(struct driver_data *drv_data) return drv_data->rx == drv_data->rx_end; } -void *pxa2xx_spi_next_transfer(struct driver_data *drv_data) -{ - struct spi_message *msg = drv_data->master->cur_msg; - struct spi_transfer *trans = drv_data->cur_transfer; - - /* Move to next transfer */ - if (trans->transfer_list.next != &msg->transfers) { - drv_data->cur_transfer = - list_entry(trans->transfer_list.next, - struct spi_transfer, - transfer_list); - return RUNNING_STATE; - } else - return DONE_STATE; -} - -/* caller already set message->status; dma and pio irqs are blocked */ -static void giveback(struct driver_data *drv_data) -{ - struct spi_transfer* last_transfer; - struct spi_message *msg; - - msg = drv_data->master->cur_msg; - drv_data->cur_transfer = NULL; - - last_transfer = list_last_entry(&msg->transfers, struct spi_transfer, - transfer_list); - - /* Delay if requested before any change in chip select */ - if (last_transfer->delay_usecs) - udelay(last_transfer->delay_usecs); - - /* Drop chip select UNLESS cs_change is true or we are returning - * a message with an error, or next message is for another chip - */ - if (!last_transfer->cs_change) - cs_deassert(drv_data); - else { - struct spi_message *next_msg; - - /* Holding of cs was hinted, but we need to make sure - * the next message is for the same chip. Don't waste - * time with the following tests unless this was hinted. - * - * We cannot postpone this until pump_messages, because - * after calling msg->complete (below) the driver that - * sent the current message could be unloaded, which - * could invalidate the cs_control() callback... - */ - - /* get a pointer to the next message, if any */ - next_msg = spi_get_next_queued_message(drv_data->master); - - /* see if the next and current messages point - * to the same chip - */ - if ((next_msg && next_msg->spi != msg->spi) || - msg->state == ERROR_STATE) - cs_deassert(drv_data); - } - - spi_finalize_current_message(drv_data->master); -} - static void reset_sccr1(struct driver_data *drv_data) { struct chip_data *chip = @@ -648,8 +598,8 @@ static void int_error_stop(struct driver_data *drv_data, const char* msg) dev_err(&drv_data->pdev->dev, "%s\n", msg); - drv_data->master->cur_msg->state = ERROR_STATE; - tasklet_schedule(&drv_data->pump_transfers); + drv_data->master->cur_msg->status = -EIO; + spi_finalize_current_transfer(drv_data->master); } static void int_transfer_complete(struct driver_data *drv_data) @@ -660,19 +610,7 @@ static void int_transfer_complete(struct driver_data *drv_data) if (!pxa25x_ssp_comp(drv_data)) pxa2xx_spi_write(drv_data, SSTO, 0); - /* Update total byte transferred return count actual bytes read */ - drv_data->master->cur_msg->actual_length += drv_data->len - - (drv_data->rx_end - drv_data->rx); - - /* Transfer delays and chip select release are - * handled in pump_transfers or giveback - */ - - /* Move to next transfer */ - drv_data->master->cur_msg->state = pxa2xx_spi_next_transfer(drv_data); - - /* Schedule transfer tasklet */ - tasklet_schedule(&drv_data->pump_transfers); + spi_finalize_current_transfer(drv_data->master); } static irqreturn_t interrupt_transfer(struct driver_data *drv_data) @@ -973,17 +911,16 @@ static bool pxa2xx_spi_can_dma(struct spi_controller *master, xfer->len >= chip->dma_burst_size; } -static void pump_transfers(unsigned long data) +static int pxa2xx_spi_transfer_one(struct spi_controller *master, + struct spi_device *spi, + struct spi_transfer *transfer) { - struct driver_data *drv_data = (struct driver_data *)data; - struct spi_controller *master = drv_data->master; + struct driver_data *drv_data = spi_controller_get_devdata(master); struct spi_message *message = master->cur_msg; struct chip_data *chip = spi_get_ctldata(message->spi); u32 dma_thresh = chip->dma_threshold; u32 dma_burst = chip->dma_burst_size; u32 change_mask = pxa2xx_spi_get_ssrc1_change_mask(drv_data); - struct spi_transfer *transfer; - struct spi_transfer *previous; u32 clk_div; u8 bits; u32 speed; @@ -992,36 +929,6 @@ static void pump_transfers(unsigned long data) int err; int dma_mapped; - /* Get current state information */ - transfer = drv_data->cur_transfer; - - /* Handle for abort */ - if (message->state == ERROR_STATE) { - message->status = -EIO; - giveback(drv_data); - return; - } - - /* Handle end of message */ - if (message->state == DONE_STATE) { - message->status = 0; - giveback(drv_data); - return; - } - - /* Delay if requested at end of transfer before CS change */ - if (message->state == RUNNING_STATE) { - previous = list_entry(transfer->transfer_list.prev, - struct spi_transfer, - transfer_list); - if (previous->delay_usecs) - udelay(previous->delay_usecs); - - /* Drop chip select only if cs_change is requested */ - if (previous->cs_change) - cs_deassert(drv_data); - } - /* Check if we can DMA this transfer */ if (transfer->len > MAX_DMA_LEN && chip->enable_dma) { @@ -1029,34 +936,27 @@ static void pump_transfers(unsigned long data) if (message->is_dma_mapped || transfer->rx_dma || transfer->tx_dma) { dev_err(&drv_data->pdev->dev, - "pump_transfers: mapped transfer length of " - "%u is greater than %d\n", + "Mapped transfer length of %u is greater than %d\n", transfer->len, MAX_DMA_LEN); - message->status = -EINVAL; - giveback(drv_data); - return; + return -EINVAL; } /* warn ... we force this to PIO mode */ dev_warn_ratelimited(&message->spi->dev, - "pump_transfers: DMA disabled for transfer length %ld " - "greater than %d\n", - (long)drv_data->len, MAX_DMA_LEN); + "DMA disabled for transfer length %ld greater than %d\n", + (long)transfer->len, MAX_DMA_LEN); } /* Setup the transfer state based on the type of transfer */ if (pxa2xx_spi_flush(drv_data) == 0) { - dev_err(&drv_data->pdev->dev, "pump_transfers: flush failed\n"); - message->status = -EIO; - giveback(drv_data); - return; + dev_err(&drv_data->pdev->dev, "Flush failed\n"); + return -EIO; } drv_data->n_bytes = chip->n_bytes; drv_data->tx = (void *)transfer->tx_buf; drv_data->tx_end = drv_data->tx + transfer->len; drv_data->rx = transfer->rx_buf; drv_data->rx_end = drv_data->rx + transfer->len; - drv_data->len = transfer->len; drv_data->write = drv_data->tx ? chip->write : null_writer; drv_data->read = drv_data->rx ? chip->read : null_reader; @@ -1095,11 +995,9 @@ static void pump_transfers(unsigned long data) bits, &dma_burst, &dma_thresh)) dev_warn_ratelimited(&message->spi->dev, - "pump_transfers: DMA burst size reduced to match bits_per_word\n"); + "DMA burst size reduced to match bits_per_word\n"); } - message->state = RUNNING_STATE; - dma_mapped = master->can_dma && master->can_dma(master, message->spi, transfer) && master->cur_msg_mapped; @@ -1108,12 +1006,9 @@ static void pump_transfers(unsigned long data) /* Ensure we have the correct interrupt handler */ drv_data->transfer_handler = pxa2xx_spi_dma_transfer; - err = pxa2xx_spi_dma_prepare(drv_data, dma_burst); - if (err) { - message->status = err; - giveback(drv_data); - return; - } + err = pxa2xx_spi_dma_prepare(drv_data, transfer); + if (err) + return err; /* Clear status and start DMA engine */ cr1 = chip->cr1 | dma_thresh | drv_data->dma_cr1; @@ -1175,27 +1070,40 @@ static void pump_transfers(unsigned long data) pxa2xx_spi_write(drv_data, SSTO, chip->timeout); } - cs_assert(drv_data); - - /* after chip select, release the data by enabling service - * requests and interrupts, without changing any mode bits */ + /* + * Release the data by enabling service requests and interrupts, + * without changing any mode bits + */ pxa2xx_spi_write(drv_data, SSCR1, cr1); + + return 1; } -static int pxa2xx_spi_transfer_one_message(struct spi_controller *master, - struct spi_message *msg) +static void pxa2xx_spi_handle_err(struct spi_controller *master, + struct spi_message *msg) { struct driver_data *drv_data = spi_controller_get_devdata(master); - /* Initial message state*/ - msg->state = START_STATE; - drv_data->cur_transfer = list_entry(msg->transfers.next, - struct spi_transfer, - transfer_list); + /* Disable the SSP */ + pxa2xx_spi_write(drv_data, SSCR0, + pxa2xx_spi_read(drv_data, SSCR0) & ~SSCR0_SSE); + /* Clear and disable interrupts and service requests */ + write_SSSR_CS(drv_data, drv_data->clear_sr); + pxa2xx_spi_write(drv_data, SSCR1, + pxa2xx_spi_read(drv_data, SSCR1) + & ~(drv_data->int_cr1 | drv_data->dma_cr1)); + if (!pxa25x_ssp_comp(drv_data)) + pxa2xx_spi_write(drv_data, SSTO, 0); - /* Mark as busy and launch transfers */ - tasklet_schedule(&drv_data->pump_transfers); - return 0; + /* + * Stop the DMA if running. Note DMA callback handler may have unset + * the dma_running already, which is fine as stopping is not needed + * then but we shouldn't rely this flag for anything else than + * stopping. For instance to differentiate between PIO and DMA + * transfers. + */ + if (atomic_read(&drv_data->dma_running)) + pxa2xx_spi_dma_stop(drv_data); } static int pxa2xx_spi_unprepare_transfer(struct spi_controller *master) @@ -1651,7 +1559,9 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) master->dma_alignment = DMA_ALIGNMENT; master->cleanup = cleanup; master->setup = setup; - master->transfer_one_message = pxa2xx_spi_transfer_one_message; + master->set_cs = pxa2xx_spi_set_cs; + master->transfer_one = pxa2xx_spi_transfer_one; + master->handle_err = pxa2xx_spi_handle_err; master->unprepare_transfer_hardware = pxa2xx_spi_unprepare_transfer; master->fw_translate_cs = pxa2xx_spi_fw_translate_cs; master->auto_runtime_pm = true; @@ -1702,7 +1612,9 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) } /* Enable SOC clock */ - clk_prepare_enable(ssp->clk); + status = clk_prepare_enable(ssp->clk); + if (status) + goto out_error_dma_irq_alloc; master->max_speed_hz = clk_get_rate(ssp->clk); @@ -1787,9 +1699,6 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) } } - tasklet_init(&drv_data->pump_transfers, pump_transfers, - (unsigned long)drv_data); - pm_runtime_set_autosuspend_delay(&pdev->dev, 50); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_active(&pdev->dev); @@ -1809,6 +1718,8 @@ out_error_clock_enabled: pm_runtime_put_noidle(&pdev->dev); pm_runtime_disable(&pdev->dev); clk_disable_unprepare(ssp->clk); + +out_error_dma_irq_alloc: pxa2xx_spi_dma_release(drv_data); free_irq(ssp->irq, drv_data); @@ -1882,8 +1793,11 @@ static int pxa2xx_spi_resume(struct device *dev) int status; /* Enable the SSP clock */ - if (!pm_runtime_suspended(dev)) - clk_prepare_enable(ssp->clk); + if (!pm_runtime_suspended(dev)) { + status = clk_prepare_enable(ssp->clk); + if (status) + return status; + } /* Restore LPSS private register bits */ if (is_lpss_ssp(drv_data)) @@ -1912,9 +1826,10 @@ static int pxa2xx_spi_runtime_suspend(struct device *dev) static int pxa2xx_spi_runtime_resume(struct device *dev) { struct driver_data *drv_data = dev_get_drvdata(dev); + int status; - clk_prepare_enable(drv_data->ssp->clk); - return 0; + status = clk_prepare_enable(drv_data->ssp->clk); + return status; } #endif diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h index 0ae7defd3492..513c53aaeab2 100644 --- a/drivers/spi/spi-pxa2xx.h +++ b/drivers/spi/spi-pxa2xx.h @@ -46,15 +46,10 @@ struct driver_data { u32 clear_sr; u32 mask_sr; - /* Message Transfer pump */ - struct tasklet_struct pump_transfers; - /* DMA engine support */ atomic_t dma_running; - /* Current message transfer state info */ - struct spi_transfer *cur_transfer; - size_t len; + /* Current transfer state info */ void *tx; void *tx_end; void *rx; @@ -104,11 +99,6 @@ static inline void pxa2xx_spi_write(const struct driver_data *drv_data, __raw_writel(val, drv_data->ioaddr + reg); } -#define START_STATE ((void *)0) -#define RUNNING_STATE ((void *)1) -#define DONE_STATE ((void *)2) -#define ERROR_STATE ((void *)-1) - #define DMA_ALIGNMENT 8 static inline int pxa25x_ssp_comp(struct driver_data *drv_data) @@ -133,14 +123,15 @@ static inline void write_SSSR_CS(struct driver_data *drv_data, u32 val) } extern int pxa2xx_spi_flush(struct driver_data *drv_data); -extern void *pxa2xx_spi_next_transfer(struct driver_data *drv_data); #define MAX_DMA_LEN SZ_64K #define DEFAULT_DMA_CR1 (SSCR1_TSRE | SSCR1_RSRE | SSCR1_TRAIL) extern irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data); -extern int pxa2xx_spi_dma_prepare(struct driver_data *drv_data, u32 dma_burst); +extern int pxa2xx_spi_dma_prepare(struct driver_data *drv_data, + struct spi_transfer *xfer); extern void pxa2xx_spi_dma_start(struct driver_data *drv_data); +extern void pxa2xx_spi_dma_stop(struct driver_data *drv_data); extern int pxa2xx_spi_dma_setup(struct driver_data *drv_data); extern void pxa2xx_spi_dma_release(struct driver_data *drv_data); extern int pxa2xx_spi_set_dma_burst_and_threshold(struct chip_data *chip, diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index baa3a9fa2638..7b7151ec14c8 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -28,15 +28,15 @@ #define S3C64XX_SPI_CH_CFG 0x00 #define S3C64XX_SPI_CLK_CFG 0x04 -#define S3C64XX_SPI_MODE_CFG 0x08 -#define S3C64XX_SPI_SLAVE_SEL 0x0C +#define S3C64XX_SPI_MODE_CFG 0x08 +#define S3C64XX_SPI_SLAVE_SEL 0x0C #define S3C64XX_SPI_INT_EN 0x10 #define S3C64XX_SPI_STATUS 0x14 #define S3C64XX_SPI_TX_DATA 0x18 #define S3C64XX_SPI_RX_DATA 0x1C -#define S3C64XX_SPI_PACKET_CNT 0x20 -#define S3C64XX_SPI_PENDING_CLR 0x24 -#define S3C64XX_SPI_SWAP_CFG 0x28 +#define S3C64XX_SPI_PACKET_CNT 0x20 +#define S3C64XX_SPI_PENDING_CLR 0x24 +#define S3C64XX_SPI_SWAP_CFG 0x28 #define S3C64XX_SPI_FB_CLK 0x2C #define S3C64XX_SPI_CH_HS_EN (1<<6) /* High Speed Enable */ @@ -77,9 +77,9 @@ #define S3C64XX_SPI_INT_TX_FIFORDY_EN (1<<0) #define S3C64XX_SPI_ST_RX_OVERRUN_ERR (1<<5) -#define S3C64XX_SPI_ST_RX_UNDERRUN_ERR (1<<4) +#define S3C64XX_SPI_ST_RX_UNDERRUN_ERR (1<<4) #define S3C64XX_SPI_ST_TX_OVERRUN_ERR (1<<3) -#define S3C64XX_SPI_ST_TX_UNDERRUN_ERR (1<<2) +#define S3C64XX_SPI_ST_TX_UNDERRUN_ERR (1<<2) #define S3C64XX_SPI_ST_RX_FIFORDY (1<<1) #define S3C64XX_SPI_ST_TX_FIFORDY (1<<0) @@ -100,7 +100,7 @@ #define S3C64XX_SPI_SWAP_TX_BIT (1<<1) #define S3C64XX_SPI_SWAP_TX_EN (1<<0) -#define S3C64XX_SPI_FBCLK_MSK (3<<0) +#define S3C64XX_SPI_FBCLK_MSK (3<<0) #define FIFO_LVL_MASK(i) ((i)->port_conf->fifo_lvl_mask[i->port_id]) #define S3C64XX_SPI_ST_TX_DONE(v, i) (((v) & \ @@ -156,7 +156,6 @@ struct s3c64xx_spi_port_config { * @ioclk: Pointer to the i/o clock between master and slave * @master: Pointer to the SPI Protocol master. * @cntrlr_info: Platform specific data for the controller this driver manages. - * @tgl_spi: Pointer to the last CS left untoggled by the cs_change hint. * @lock: Controller specific lock. * @state: Set of FLAGS to indicate status. * @rx_dmach: Controller's DMA channel for Rx. @@ -177,7 +176,6 @@ struct s3c64xx_spi_driver_data { struct platform_device *pdev; struct spi_master *master; struct s3c64xx_spi_info *cntrlr_info; - struct spi_device *tgl_spi; spinlock_t lock; unsigned long sfr_start; struct completion xfer_completion; @@ -190,7 +188,7 @@ struct s3c64xx_spi_driver_data { unsigned int port_id; }; -static void flush_fifo(struct s3c64xx_spi_driver_data *sdd) +static void s3c64xx_flush_fifo(struct s3c64xx_spi_driver_data *sdd) { void __iomem *regs = sdd->regs; unsigned long loops; @@ -350,9 +348,8 @@ static bool s3c64xx_spi_can_dma(struct spi_master *master, return xfer->len > (FIFO_LVL_MASK(sdd) >> 1) + 1; } -static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, - struct spi_device *spi, - struct spi_transfer *xfer, int dma_mode) +static void s3c64xx_enable_datapath(struct s3c64xx_spi_driver_data *sdd, + struct spi_transfer *xfer, int dma_mode) { void __iomem *regs = sdd->regs; u32 modecfg, chcfg; @@ -442,8 +439,8 @@ static u32 s3c64xx_spi_wait_for_timeout(struct s3c64xx_spi_driver_data *sdd, return RX_FIFO_LVL(status, sdd); } -static int wait_for_dma(struct s3c64xx_spi_driver_data *sdd, - struct spi_transfer *xfer) +static int s3c64xx_wait_for_dma(struct s3c64xx_spi_driver_data *sdd, + struct spi_transfer *xfer) { void __iomem *regs = sdd->regs; unsigned long val; @@ -485,8 +482,8 @@ static int wait_for_dma(struct s3c64xx_spi_driver_data *sdd, return 0; } -static int wait_for_pio(struct s3c64xx_spi_driver_data *sdd, - struct spi_transfer *xfer) +static int s3c64xx_wait_for_pio(struct s3c64xx_spi_driver_data *sdd, + struct spi_transfer *xfer) { void __iomem *regs = sdd->regs; unsigned long val; @@ -505,6 +502,8 @@ static int wait_for_pio(struct s3c64xx_spi_driver_data *sdd, status = readl(regs + S3C64XX_SPI_STATUS); } while (RX_FIFO_LVL(status, sdd) < xfer->len && --val); + if (!val) + return -EIO; /* If it was only Tx */ if (!xfer->rx_buf) { @@ -635,11 +634,15 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master, struct spi_transfer *xfer) { struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); + const unsigned int fifo_len = (FIFO_LVL_MASK(sdd) >> 1) + 1; + const void *tx_buf = NULL; + void *rx_buf = NULL; + int target_len = 0, origin_len = 0; + int use_dma = 0; int status; u32 speed; u8 bpw; unsigned long flags; - int use_dma; reinit_completion(&sdd->xfer_completion); @@ -654,48 +657,77 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master, s3c64xx_spi_config(sdd); } - /* Polling method for xfers not bigger than FIFO capacity */ - use_dma = 0; - if (!is_polling(sdd) && - (sdd->rx_dma.ch && sdd->tx_dma.ch && - (xfer->len > ((FIFO_LVL_MASK(sdd) >> 1) + 1)))) + if (!is_polling(sdd) && (xfer->len > fifo_len) && + sdd->rx_dma.ch && sdd->tx_dma.ch) { use_dma = 1; - spin_lock_irqsave(&sdd->lock, flags); + } else if (is_polling(sdd) && xfer->len > fifo_len) { + tx_buf = xfer->tx_buf; + rx_buf = xfer->rx_buf; + origin_len = xfer->len; - /* Pending only which is to be done */ - sdd->state &= ~RXBUSY; - sdd->state &= ~TXBUSY; + target_len = xfer->len; + if (xfer->len > fifo_len) + xfer->len = fifo_len; + } - enable_datapath(sdd, spi, xfer, use_dma); + do { + spin_lock_irqsave(&sdd->lock, flags); - /* Start the signals */ - s3c64xx_spi_set_cs(spi, true); + /* Pending only which is to be done */ + sdd->state &= ~RXBUSY; + sdd->state &= ~TXBUSY; - spin_unlock_irqrestore(&sdd->lock, flags); + s3c64xx_enable_datapath(sdd, xfer, use_dma); - if (use_dma) - status = wait_for_dma(sdd, xfer); - else - status = wait_for_pio(sdd, xfer); - - if (status) { - dev_err(&spi->dev, "I/O Error: rx-%d tx-%d res:rx-%c tx-%c len-%d\n", - xfer->rx_buf ? 1 : 0, xfer->tx_buf ? 1 : 0, - (sdd->state & RXBUSY) ? 'f' : 'p', - (sdd->state & TXBUSY) ? 'f' : 'p', - xfer->len); - - if (use_dma) { - if (xfer->tx_buf != NULL - && (sdd->state & TXBUSY)) - dmaengine_terminate_all(sdd->tx_dma.ch); - if (xfer->rx_buf != NULL - && (sdd->state & RXBUSY)) - dmaengine_terminate_all(sdd->rx_dma.ch); + /* Start the signals */ + s3c64xx_spi_set_cs(spi, true); + + spin_unlock_irqrestore(&sdd->lock, flags); + + if (use_dma) + status = s3c64xx_wait_for_dma(sdd, xfer); + else + status = s3c64xx_wait_for_pio(sdd, xfer); + + if (status) { + dev_err(&spi->dev, + "I/O Error: rx-%d tx-%d res:rx-%c tx-%c len-%d\n", + xfer->rx_buf ? 1 : 0, xfer->tx_buf ? 1 : 0, + (sdd->state & RXBUSY) ? 'f' : 'p', + (sdd->state & TXBUSY) ? 'f' : 'p', + xfer->len); + + if (use_dma) { + if (xfer->tx_buf && (sdd->state & TXBUSY)) + dmaengine_terminate_all(sdd->tx_dma.ch); + if (xfer->rx_buf && (sdd->state & RXBUSY)) + dmaengine_terminate_all(sdd->rx_dma.ch); + } + } else { + s3c64xx_flush_fifo(sdd); } - } else { - flush_fifo(sdd); + if (target_len > 0) { + target_len -= xfer->len; + + if (xfer->tx_buf) + xfer->tx_buf += xfer->len; + + if (xfer->rx_buf) + xfer->rx_buf += xfer->len; + + if (target_len > fifo_len) + xfer->len = fifo_len; + else + xfer->len = target_len; + } + } while (target_len > 0); + + if (origin_len) { + /* Restore original xfer buffers and length */ + xfer->tx_buf = tx_buf; + xfer->rx_buf = rx_buf; + xfer->len = origin_len; } return status; @@ -891,7 +923,7 @@ static irqreturn_t s3c64xx_spi_irq(int irq, void *data) return IRQ_HANDLED; } -static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel) +static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd) { struct s3c64xx_spi_info *sci = sdd->cntrlr_info; void __iomem *regs = sdd->regs; @@ -929,7 +961,7 @@ static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel) val |= (S3C64XX_SPI_TRAILCNT << S3C64XX_SPI_TRAILCNT_OFF); writel(val, regs + S3C64XX_SPI_MODE_CFG); - flush_fifo(sdd); + s3c64xx_flush_fifo(sdd); } #ifdef CONFIG_OF @@ -1145,7 +1177,7 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) pm_runtime_get_sync(&pdev->dev); /* Setup Deufult Mode */ - s3c64xx_spi_hwinit(sdd, sdd->port_id); + s3c64xx_spi_hwinit(sdd); spin_lock_init(&sdd->lock); init_completion(&sdd->xfer_completion); @@ -1260,8 +1292,6 @@ static int s3c64xx_spi_resume(struct device *dev) if (ret < 0) return ret; - s3c64xx_spi_hwinit(sdd, sdd->port_id); - return spi_master_resume(master); } #endif /* CONFIG_PM_SLEEP */ @@ -1299,6 +1329,8 @@ static int s3c64xx_spi_runtime_resume(struct device *dev) if (ret != 0) goto err_disable_src_clk; + s3c64xx_spi_hwinit(sdd); + return 0; err_disable_src_clk: @@ -1344,15 +1376,6 @@ static struct s3c64xx_spi_port_config exynos4_spi_port_config = { .clk_from_cmu = true, }; -static struct s3c64xx_spi_port_config exynos5440_spi_port_config = { - .fifo_lvl_mask = { 0x1ff }, - .rx_lvl_offset = 15, - .tx_st_done = 25, - .high_speed = true, - .clk_from_cmu = true, - .quirks = S3C64XX_SPI_QUIRK_POLL, -}; - static struct s3c64xx_spi_port_config exynos7_spi_port_config = { .fifo_lvl_mask = { 0x1ff, 0x7F, 0x7F, 0x7F, 0x7F, 0x1ff}, .rx_lvl_offset = 15, @@ -1396,9 +1419,6 @@ static const struct of_device_id s3c64xx_spi_dt_match[] = { { .compatible = "samsung,exynos4210-spi", .data = (void *)&exynos4_spi_port_config, }, - { .compatible = "samsung,exynos5440-spi", - .data = (void *)&exynos5440_spi_port_config, - }, { .compatible = "samsung,exynos7-spi", .data = (void *)&exynos7_spi_port_config, }, diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 8171eedbfc90..0e74cbf9929d 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -39,7 +39,7 @@ struct sh_msiof_chipdata { u16 tx_fifo_size; u16 rx_fifo_size; u16 master_flags; - u16 min_div; + u16 min_div_pow; }; struct sh_msiof_spi_priv { @@ -51,7 +51,7 @@ struct sh_msiof_spi_priv { struct completion done; unsigned int tx_fifo_size; unsigned int rx_fifo_size; - unsigned int min_div; + unsigned int min_div_pow; void *tx_dma_page; void *rx_dma_page; dma_addr_t tx_dma_addr; @@ -249,43 +249,46 @@ static irqreturn_t sh_msiof_spi_irq(int irq, void *data) return IRQ_HANDLED; } -static struct { - unsigned short div; - unsigned short brdv; -} const sh_msiof_spi_div_table[] = { - { 1, SCR_BRDV_DIV_1 }, - { 2, SCR_BRDV_DIV_2 }, - { 4, SCR_BRDV_DIV_4 }, - { 8, SCR_BRDV_DIV_8 }, - { 16, SCR_BRDV_DIV_16 }, - { 32, SCR_BRDV_DIV_32 }, +static const u32 sh_msiof_spi_div_array[] = { + SCR_BRDV_DIV_1, SCR_BRDV_DIV_2, SCR_BRDV_DIV_4, + SCR_BRDV_DIV_8, SCR_BRDV_DIV_16, SCR_BRDV_DIV_32, }; static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p, unsigned long parent_rate, u32 spi_hz) { - unsigned long div = 1024; + unsigned long div; u32 brps, scr; - size_t k; + unsigned int div_pow = p->min_div_pow; - if (!WARN_ON(!spi_hz || !parent_rate)) - div = DIV_ROUND_UP(parent_rate, spi_hz); - - div = max_t(unsigned long, div, p->min_div); + if (!spi_hz || !parent_rate) { + WARN(1, "Invalid clock rate parameters %lu and %u\n", + parent_rate, spi_hz); + return; + } - for (k = 0; k < ARRAY_SIZE(sh_msiof_spi_div_table); k++) { - brps = DIV_ROUND_UP(div, sh_msiof_spi_div_table[k].div); + div = DIV_ROUND_UP(parent_rate, spi_hz); + if (div <= 1024) { /* SCR_BRDV_DIV_1 is valid only if BRPS is x 1/1 or x 1/2 */ - if (sh_msiof_spi_div_table[k].div == 1 && brps > 2) - continue; - if (brps <= 32) /* max of brdv is 32 */ - break; - } + if (!div_pow && div <= 32 && div > 2) + div_pow = 1; + + if (div_pow) + brps = (div + 1) >> div_pow; + else + brps = div; - k = min_t(int, k, ARRAY_SIZE(sh_msiof_spi_div_table) - 1); - brps = min_t(int, brps, 32); + for (; brps > 32; div_pow++) + brps = (brps + 1) >> 1; + } else { + /* Set transfer rate composite divisor to 2^5 * 32 = 1024 */ + dev_err(&p->pdev->dev, + "Requested SPI transfer rate %d is too low\n", spi_hz); + div_pow = 5; + brps = 32; + } - scr = sh_msiof_spi_div_table[k].brdv | SCR_BRPS(brps); + scr = sh_msiof_spi_div_array[div_pow] | SCR_BRPS(brps); sh_msiof_write(p, TSCR, scr); if (!(p->master->flags & SPI_MASTER_MUST_TX)) sh_msiof_write(p, RSCR, scr); @@ -564,14 +567,16 @@ static int sh_msiof_spi_setup(struct spi_device *spi) /* Configure native chip select mode/polarity early */ clr = MDR1_SYNCMD_MASK; - set = MDR1_TRMD | TMDR1_PCON | MDR1_SYNCMD_SPI; + set = MDR1_SYNCMD_SPI; if (spi->mode & SPI_CS_HIGH) clr |= BIT(MDR1_SYNCAC_SHIFT); else set |= BIT(MDR1_SYNCAC_SHIFT); pm_runtime_get_sync(&p->pdev->dev); tmp = sh_msiof_read(p, TMDR1) & ~clr; - sh_msiof_write(p, TMDR1, tmp | set); + sh_msiof_write(p, TMDR1, tmp | set | MDR1_TRMD | TMDR1_PCON); + tmp = sh_msiof_read(p, RMDR1) & ~clr; + sh_msiof_write(p, RMDR1, tmp | set); pm_runtime_put(&p->pdev->dev); p->native_cs_high = spi->mode & SPI_CS_HIGH; p->native_cs_inited = true; @@ -1041,21 +1046,21 @@ static const struct sh_msiof_chipdata sh_data = { .tx_fifo_size = 64, .rx_fifo_size = 64, .master_flags = 0, - .min_div = 1, + .min_div_pow = 0, }; static const struct sh_msiof_chipdata rcar_gen2_data = { .tx_fifo_size = 64, .rx_fifo_size = 64, .master_flags = SPI_MASTER_MUST_TX, - .min_div = 1, + .min_div_pow = 0, }; static const struct sh_msiof_chipdata rcar_gen3_data = { .tx_fifo_size = 64, .rx_fifo_size = 64, .master_flags = SPI_MASTER_MUST_TX, - .min_div = 2, + .min_div_pow = 1, }; static const struct of_device_id sh_msiof_match[] = { @@ -1319,7 +1324,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, p); p->master = master; p->info = info; - p->min_div = chipdata->min_div; + p->min_div_pow = chipdata->min_div_pow; init_completion(&p->done); diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c index ba9743fa2326..ad1e55d3d5d5 100644 --- a/drivers/spi/spi-stm32.c +++ b/drivers/spi/spi-stm32.c @@ -1129,7 +1129,7 @@ static int stm32_spi_probe(struct platform_device *pdev) if (!spi->clk_rate) { dev_err(&pdev->dev, "clk rate = 0\n"); ret = -EINVAL; - goto err_master_put; + goto err_clk_disable; } spi->rst = devm_reset_control_get_exclusive(&pdev->dev, NULL); diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index c24d9b45a27c..5f19016bbf10 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -36,6 +36,7 @@ #include <linux/sizes.h> #include <linux/spi/spi.h> +#include <linux/spi/spi-mem.h> struct ti_qspi_regs { u32 clkctrl; @@ -50,6 +51,7 @@ struct ti_qspi { struct spi_master *master; void __iomem *base; void __iomem *mmap_base; + size_t mmap_size; struct regmap *ctrl_base; unsigned int ctrl_reg; struct clk *fclk; @@ -434,12 +436,10 @@ static int ti_qspi_dma_xfer(struct ti_qspi *qspi, dma_addr_t dma_dst, return 0; } -static int ti_qspi_dma_bounce_buffer(struct ti_qspi *qspi, - struct spi_flash_read_message *msg) +static int ti_qspi_dma_bounce_buffer(struct ti_qspi *qspi, loff_t offs, + void *to, size_t readsize) { - size_t readsize = msg->len; - void *to = msg->buf; - dma_addr_t dma_src = qspi->mmap_phys_base + msg->from; + dma_addr_t dma_src = qspi->mmap_phys_base + offs; int ret = 0; /* @@ -507,13 +507,14 @@ static void ti_qspi_disable_memory_map(struct spi_device *spi) qspi->mmap_enabled = false; } -static void ti_qspi_setup_mmap_read(struct spi_device *spi, - struct spi_flash_read_message *msg) +static void ti_qspi_setup_mmap_read(struct spi_device *spi, u8 opcode, + u8 data_nbits, u8 addr_width, + u8 dummy_bytes) { struct ti_qspi *qspi = spi_master_get_devdata(spi->master); - u32 memval = msg->read_opcode; + u32 memval = opcode; - switch (msg->data_nbits) { + switch (data_nbits) { case SPI_NBITS_QUAD: memval |= QSPI_SETUP_RD_QUAD; break; @@ -524,48 +525,64 @@ static void ti_qspi_setup_mmap_read(struct spi_device *spi, memval |= QSPI_SETUP_RD_NORMAL; break; } - memval |= ((msg->addr_width - 1) << QSPI_SETUP_ADDR_SHIFT | - msg->dummy_bytes << QSPI_SETUP_DUMMY_SHIFT); + memval |= ((addr_width - 1) << QSPI_SETUP_ADDR_SHIFT | + dummy_bytes << QSPI_SETUP_DUMMY_SHIFT); ti_qspi_write(qspi, memval, QSPI_SPI_SETUP_REG(spi->chip_select)); } -static bool ti_qspi_spi_flash_can_dma(struct spi_device *spi, - struct spi_flash_read_message *msg) +static int ti_qspi_exec_mem_op(struct spi_mem *mem, + const struct spi_mem_op *op) { - return virt_addr_valid(msg->buf); -} - -static int ti_qspi_spi_flash_read(struct spi_device *spi, - struct spi_flash_read_message *msg) -{ - struct ti_qspi *qspi = spi_master_get_devdata(spi->master); + struct ti_qspi *qspi = spi_master_get_devdata(mem->spi->master); + u32 from = 0; int ret = 0; + /* Only optimize read path. */ + if (!op->data.nbytes || op->data.dir != SPI_MEM_DATA_IN || + !op->addr.nbytes || op->addr.nbytes > 4) + return -ENOTSUPP; + + /* Address exceeds MMIO window size, fall back to regular mode. */ + from = op->addr.val; + if (from + op->data.nbytes > qspi->mmap_size) + return -ENOTSUPP; + mutex_lock(&qspi->list_lock); if (!qspi->mmap_enabled) - ti_qspi_enable_memory_map(spi); - ti_qspi_setup_mmap_read(spi, msg); + ti_qspi_enable_memory_map(mem->spi); + ti_qspi_setup_mmap_read(mem->spi, op->cmd.opcode, op->data.buswidth, + op->addr.nbytes, op->dummy.nbytes); if (qspi->rx_chan) { - if (msg->cur_msg_mapped) - ret = ti_qspi_dma_xfer_sg(qspi, msg->rx_sg, msg->from); - else - ret = ti_qspi_dma_bounce_buffer(qspi, msg); - if (ret) - goto err_unlock; + struct sg_table sgt; + + if (virt_addr_valid(op->data.buf.in) && + !spi_controller_dma_map_mem_op_data(mem->spi->master, op, + &sgt)) { + ret = ti_qspi_dma_xfer_sg(qspi, sgt, from); + spi_controller_dma_unmap_mem_op_data(mem->spi->master, + op, &sgt); + } else { + ret = ti_qspi_dma_bounce_buffer(qspi, from, + op->data.buf.in, + op->data.nbytes); + } } else { - memcpy_fromio(msg->buf, qspi->mmap_base + msg->from, msg->len); + memcpy_fromio(op->data.buf.in, qspi->mmap_base + from, + op->data.nbytes); } - msg->retlen = msg->len; -err_unlock: mutex_unlock(&qspi->list_lock); return ret; } +static const struct spi_controller_mem_ops ti_qspi_mem_ops = { + .exec_op = ti_qspi_exec_mem_op, +}; + static int ti_qspi_start_transfer_one(struct spi_master *master, struct spi_message *m) { @@ -672,7 +689,7 @@ static int ti_qspi_probe(struct platform_device *pdev) master->dev.of_node = pdev->dev.of_node; master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) | SPI_BPW_MASK(8); - master->spi_flash_read = ti_qspi_spi_flash_read; + master->mem_ops = &ti_qspi_mem_ops; if (!of_property_read_u32(np, "num-cs", &num_cs)) master->num_chipselect = num_cs; @@ -702,6 +719,9 @@ static int ti_qspi_probe(struct platform_device *pdev) } } + if (res_mmap) + qspi->mmap_size = resource_size(res_mmap); + irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "no irq resource?\n"); @@ -770,7 +790,6 @@ static int ti_qspi_probe(struct platform_device *pdev) dma_release_channel(qspi->rx_chan); goto no_dma; } - master->spi_flash_can_dma = ti_qspi_spi_flash_can_dma; master->dma_rx = qspi->rx_chan; init_completion(&qspi->transfer_complete); if (res_mmap) @@ -784,7 +803,7 @@ no_dma: "mmap failed with error %ld using PIO mode\n", PTR_ERR(qspi->mmap_base)); qspi->mmap_base = NULL; - master->spi_flash_read = NULL; + master->mem_ops = NULL; } } qspi->mmap_enabled = false; diff --git a/drivers/spi/spi-zynqmp-gqspi.c b/drivers/spi/spi-zynqmp-gqspi.c index 18aeaceee286..cc4d31033494 100644 --- a/drivers/spi/spi-zynqmp-gqspi.c +++ b/drivers/spi/spi-zynqmp-gqspi.c @@ -20,6 +20,7 @@ #include <linux/of_irq.h> #include <linux/of_address.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/spi/spi.h> #include <linux/spinlock.h> #include <linux/workqueue.h> @@ -135,6 +136,7 @@ #define GQSPI_DMA_UNALIGN 0x3 #define GQSPI_DEFAULT_NUM_CS 1 /* Default number of chip selects */ +#define SPI_AUTOSUSPEND_TIMEOUT 3000 enum mode_type {GQSPI_MODE_IO, GQSPI_MODE_DMA}; /** @@ -356,21 +358,9 @@ static void zynqmp_qspi_copy_read_data(struct zynqmp_qspi *xqspi, static int zynqmp_prepare_transfer_hardware(struct spi_master *master) { struct zynqmp_qspi *xqspi = spi_master_get_devdata(master); - int ret; - - ret = clk_enable(xqspi->refclk); - if (ret) - return ret; - - ret = clk_enable(xqspi->pclk); - if (ret) - goto clk_err; zynqmp_gqspi_write(xqspi, GQSPI_EN_OFST, GQSPI_EN_MASK); return 0; -clk_err: - clk_disable(xqspi->refclk); - return ret; } /** @@ -387,8 +377,6 @@ static int zynqmp_unprepare_transfer_hardware(struct spi_master *master) struct zynqmp_qspi *xqspi = spi_master_get_devdata(master); zynqmp_gqspi_write(xqspi, GQSPI_EN_OFST, 0x0); - clk_disable(xqspi->refclk); - clk_disable(xqspi->pclk); return 0; } @@ -918,8 +906,7 @@ static int zynqmp_qspi_start_transfer(struct spi_master *master, */ static int __maybe_unused zynqmp_qspi_suspend(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct spi_master *master = platform_get_drvdata(pdev); + struct spi_master *master = dev_get_drvdata(dev); spi_master_suspend(master); @@ -939,8 +926,7 @@ static int __maybe_unused zynqmp_qspi_suspend(struct device *dev) */ static int __maybe_unused zynqmp_qspi_resume(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct spi_master *master = platform_get_drvdata(pdev); + struct spi_master *master = dev_get_drvdata(dev); struct zynqmp_qspi *xqspi = spi_master_get_devdata(master); int ret = 0; @@ -959,11 +945,67 @@ static int __maybe_unused zynqmp_qspi_resume(struct device *dev) spi_master_resume(master); + clk_disable(xqspi->refclk); + clk_disable(xqspi->pclk); return 0; } -static SIMPLE_DEV_PM_OPS(zynqmp_qspi_dev_pm_ops, zynqmp_qspi_suspend, - zynqmp_qspi_resume); +/** + * zynqmp_runtime_suspend - Runtime suspend method for the SPI driver + * @dev: Address of the platform_device structure + * + * This function disables the clocks + * + * Return: Always 0 + */ +static int __maybe_unused zynqmp_runtime_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct spi_master *master = platform_get_drvdata(pdev); + struct zynqmp_qspi *xqspi = spi_master_get_devdata(master); + + clk_disable(xqspi->refclk); + clk_disable(xqspi->pclk); + + return 0; +} + +/** + * zynqmp_runtime_resume - Runtime resume method for the SPI driver + * @dev: Address of the platform_device structure + * + * This function enables the clocks + * + * Return: 0 on success and error value on error + */ +static int __maybe_unused zynqmp_runtime_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct spi_master *master = platform_get_drvdata(pdev); + struct zynqmp_qspi *xqspi = spi_master_get_devdata(master); + int ret; + + ret = clk_enable(xqspi->pclk); + if (ret) { + dev_err(dev, "Cannot enable APB clock.\n"); + return ret; + } + + ret = clk_enable(xqspi->refclk); + if (ret) { + dev_err(dev, "Cannot enable device clock.\n"); + clk_disable(xqspi->pclk); + return ret; + } + + return 0; +} + +static const struct dev_pm_ops zynqmp_qspi_dev_pm_ops = { + SET_RUNTIME_PM_OPS(zynqmp_runtime_suspend, + zynqmp_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(zynqmp_qspi_suspend, zynqmp_qspi_resume) +}; /** * zynqmp_qspi_probe: Probe method for the QSPI driver @@ -1023,9 +1065,15 @@ static int zynqmp_qspi_probe(struct platform_device *pdev) goto clk_dis_pclk; } + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); /* QSPI controller initializations */ zynqmp_qspi_init_hw(xqspi); + pm_runtime_mark_last_busy(&pdev->dev); + pm_runtime_put_autosuspend(&pdev->dev); xqspi->irq = platform_get_irq(pdev, 0); if (xqspi->irq <= 0) { ret = -ENXIO; @@ -1063,6 +1111,8 @@ static int zynqmp_qspi_probe(struct platform_device *pdev) return 0; clk_dis_all: + pm_runtime_set_suspended(&pdev->dev); + pm_runtime_disable(&pdev->dev); clk_disable_unprepare(xqspi->refclk); clk_dis_pclk: clk_disable_unprepare(xqspi->pclk); @@ -1090,6 +1140,8 @@ static int zynqmp_qspi_remove(struct platform_device *pdev) zynqmp_gqspi_write(xqspi, GQSPI_EN_OFST, 0x0); clk_disable_unprepare(xqspi->refclk); clk_disable_unprepare(xqspi->pclk); + pm_runtime_set_suspended(&pdev->dev); + pm_runtime_disable(&pdev->dev); spi_unregister_master(master); diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 7b213faa0a2b..20b5b2754830 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -28,6 +28,7 @@ #include <linux/slab.h> #include <linux/mod_devicetable.h> #include <linux/spi/spi.h> +#include <linux/spi/spi-mem.h> #include <linux/of_gpio.h> #include <linux/pm_runtime.h> #include <linux/pm_domain.h> @@ -46,6 +47,8 @@ #define CREATE_TRACE_POINTS #include <trace/events/spi.h> +#include "internals.h" + static DEFINE_IDR(spi_master_idr); static void spidev_release(struct device *dev) @@ -740,9 +743,9 @@ static void spi_set_cs(struct spi_device *spi, bool enable) } #ifdef CONFIG_HAS_DMA -static int spi_map_buf(struct spi_controller *ctlr, struct device *dev, - struct sg_table *sgt, void *buf, size_t len, - enum dma_data_direction dir) +int spi_map_buf(struct spi_controller *ctlr, struct device *dev, + struct sg_table *sgt, void *buf, size_t len, + enum dma_data_direction dir) { const bool vmalloced_buf = is_vmalloc_addr(buf); unsigned int max_seg_size = dma_get_max_seg_size(dev); @@ -821,8 +824,8 @@ static int spi_map_buf(struct spi_controller *ctlr, struct device *dev, return 0; } -static void spi_unmap_buf(struct spi_controller *ctlr, struct device *dev, - struct sg_table *sgt, enum dma_data_direction dir) +void spi_unmap_buf(struct spi_controller *ctlr, struct device *dev, + struct sg_table *sgt, enum dma_data_direction dir) { if (sgt->orig_nents) { dma_unmap_sg(dev, sgt->sgl, sgt->orig_nents, dir); @@ -907,19 +910,6 @@ static int __spi_unmap_msg(struct spi_controller *ctlr, struct spi_message *msg) return 0; } #else /* !CONFIG_HAS_DMA */ -static inline int spi_map_buf(struct spi_controller *ctlr, struct device *dev, - struct sg_table *sgt, void *buf, size_t len, - enum dma_data_direction dir) -{ - return -EINVAL; -} - -static inline void spi_unmap_buf(struct spi_controller *ctlr, - struct device *dev, struct sg_table *sgt, - enum dma_data_direction dir) -{ -} - static inline int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg) { @@ -1222,6 +1212,7 @@ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread) if (!was_busy && ctlr->auto_runtime_pm) { ret = pm_runtime_get_sync(ctlr->dev.parent); if (ret < 0) { + pm_runtime_put_noidle(ctlr->dev.parent); dev_err(&ctlr->dev, "Failed to power device: %d\n", ret); mutex_unlock(&ctlr->io_mutex); @@ -1533,6 +1524,22 @@ err_init_queue: return ret; } +/** + * spi_flush_queue - Send all pending messages in the queue from the callers' + * context + * @ctlr: controller to process queue for + * + * This should be used when one wants to ensure all pending messages have been + * sent before doing something. Is used by the spi-mem code to make sure SPI + * memory operations do not preempt regular SPI transfers that have been queued + * before the spi-mem operation. + */ +void spi_flush_queue(struct spi_controller *ctlr) +{ + if (ctlr->transfer == spi_queued_transfer) + __spi_pump_messages(ctlr, false); +} + /*-------------------------------------------------------------------------*/ #if defined(CONFIG_OF) @@ -2063,6 +2070,26 @@ static int of_spi_register_master(struct spi_controller *ctlr) } #endif +static int spi_controller_check_ops(struct spi_controller *ctlr) +{ + /* + * The controller may implement only the high-level SPI-memory like + * operations if it does not support regular SPI transfers, and this is + * valid use case. + * If ->mem_ops is NULL, we request that at least one of the + * ->transfer_xxx() method be implemented. + */ + if (ctlr->mem_ops) { + if (!ctlr->mem_ops->exec_op) + return -EINVAL; + } else if (!ctlr->transfer && !ctlr->transfer_one && + !ctlr->transfer_one_message) { + return -EINVAL; + } + + return 0; +} + /** * spi_register_controller - register SPI master or slave controller * @ctlr: initialized master, originally from spi_alloc_master() or @@ -2096,6 +2123,14 @@ int spi_register_controller(struct spi_controller *ctlr) if (!dev) return -ENODEV; + /* + * Make sure all necessary hooks are implemented before registering + * the SPI controller. + */ + status = spi_controller_check_ops(ctlr); + if (status) + return status; + if (!spi_controller_is_slave(ctlr)) { status = of_spi_register_master(ctlr); if (status) @@ -2161,10 +2196,14 @@ int spi_register_controller(struct spi_controller *ctlr) spi_controller_is_slave(ctlr) ? "slave" : "master", dev_name(&ctlr->dev)); - /* If we're using a queued driver, start the queue */ - if (ctlr->transfer) + /* + * If we're using a queued driver, start the queue. Note that we don't + * need the queueing logic if the driver is only supporting high-level + * memory operations. + */ + if (ctlr->transfer) { dev_info(dev, "controller is unqueued, this is deprecated\n"); - else { + } else if (ctlr->transfer_one || ctlr->transfer_one_message) { status = spi_controller_initialize_queue(ctlr); if (status) { device_del(&ctlr->dev); @@ -2894,6 +2933,13 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message) { struct spi_controller *ctlr = spi->controller; + /* + * Some controllers do not support doing regular SPI transfers. Return + * ENOTSUPP when this is the case. + */ + if (!ctlr->transfer) + return -ENOTSUPP; + message->spi = spi; SPI_STATISTICS_INCREMENT_FIELD(&ctlr->statistics, spi_async); @@ -3010,63 +3056,6 @@ int spi_async_locked(struct spi_device *spi, struct spi_message *message) } EXPORT_SYMBOL_GPL(spi_async_locked); - -int spi_flash_read(struct spi_device *spi, - struct spi_flash_read_message *msg) - -{ - struct spi_controller *master = spi->controller; - struct device *rx_dev = NULL; - int ret; - - if ((msg->opcode_nbits == SPI_NBITS_DUAL || - msg->addr_nbits == SPI_NBITS_DUAL) && - !(spi->mode & (SPI_TX_DUAL | SPI_TX_QUAD))) - return -EINVAL; - if ((msg->opcode_nbits == SPI_NBITS_QUAD || - msg->addr_nbits == SPI_NBITS_QUAD) && - !(spi->mode & SPI_TX_QUAD)) - return -EINVAL; - if (msg->data_nbits == SPI_NBITS_DUAL && - !(spi->mode & (SPI_RX_DUAL | SPI_RX_QUAD))) - return -EINVAL; - if (msg->data_nbits == SPI_NBITS_QUAD && - !(spi->mode & SPI_RX_QUAD)) - return -EINVAL; - - if (master->auto_runtime_pm) { - ret = pm_runtime_get_sync(master->dev.parent); - if (ret < 0) { - dev_err(&master->dev, "Failed to power device: %d\n", - ret); - return ret; - } - } - - mutex_lock(&master->bus_lock_mutex); - mutex_lock(&master->io_mutex); - if (master->dma_rx && master->spi_flash_can_dma(spi, msg)) { - rx_dev = master->dma_rx->device->dev; - ret = spi_map_buf(master, rx_dev, &msg->rx_sg, - msg->buf, msg->len, - DMA_FROM_DEVICE); - if (!ret) - msg->cur_msg_mapped = true; - } - ret = master->spi_flash_read(spi, msg); - if (msg->cur_msg_mapped) - spi_unmap_buf(master, rx_dev, &msg->rx_sg, - DMA_FROM_DEVICE); - mutex_unlock(&master->io_mutex); - mutex_unlock(&master->bus_lock_mutex); - - if (master->auto_runtime_pm) - pm_runtime_put(master->dev.parent); - - return ret; -} -EXPORT_SYMBOL_GPL(spi_flash_read); - /*-------------------------------------------------------------------------*/ /* Utility methods for SPI protocol drivers, layered on diff --git a/drivers/staging/comedi/drivers/serial2002.c b/drivers/staging/comedi/drivers/serial2002.c index b3f3b4a201af..5471b2212a62 100644 --- a/drivers/staging/comedi/drivers/serial2002.c +++ b/drivers/staging/comedi/drivers/serial2002.c @@ -113,7 +113,7 @@ static void serial2002_tty_read_poll_wait(struct file *f, int timeout) long elapsed; __poll_t mask; - mask = f->f_op->poll(f, &table.pt); + mask = vfs_poll(f, &table.pt); if (mask & (EPOLLRDNORM | EPOLLRDBAND | EPOLLIN | EPOLLHUP | EPOLLERR)) { break; @@ -136,7 +136,7 @@ static int serial2002_tty_read(struct file *f, int timeout) result = -1; if (!IS_ERR(f)) { - if (f->f_op->poll) { + if (file_can_poll(f)) { serial2002_tty_read_poll_wait(f, timeout); if (kernel_read(f, &ch, 1, &pos) == 1) diff --git a/drivers/staging/ipx/af_ipx.c b/drivers/staging/ipx/af_ipx.c index 5703dd176787..208b5c161631 100644 --- a/drivers/staging/ipx/af_ipx.c +++ b/drivers/staging/ipx/af_ipx.c @@ -1965,7 +1965,7 @@ static const struct proto_ops ipx_dgram_ops = { .socketpair = sock_no_socketpair, .accept = sock_no_accept, .getname = ipx_getname, - .poll = datagram_poll, + .poll_mask = datagram_poll_mask, .ioctl = ipx_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = ipx_compat_ioctl, diff --git a/drivers/staging/ncpfs/dir.c b/drivers/staging/ncpfs/dir.c index 0c57c5c5d40a..072bcb12898f 100644 --- a/drivers/staging/ncpfs/dir.c +++ b/drivers/staging/ncpfs/dir.c @@ -823,12 +823,11 @@ static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, unsig struct ncp_server *server = NCP_SERVER(dir); struct inode *inode = NULL; struct ncp_entry_info finfo; - int error, res, len; + int res, len; __u8 __name[NCP_MAXPATHLEN + 1]; - error = -EIO; if (!ncp_conn_valid(server)) - goto finished; + return ERR_PTR(-EIO); ncp_vdbg("server lookup for %pd2\n", dentry); @@ -847,31 +846,20 @@ static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, unsig res = ncp_obtain_info(server, dir, __name, &(finfo.i)); } ncp_vdbg("looked for %pd2, res=%d\n", dentry, res); - /* - * If we didn't find an entry, make a negative dentry. - */ - if (res) - goto add_entry; - - /* - * Create an inode for the entry. - */ - finfo.opened = 0; - finfo.ino = iunique(dir->i_sb, 2); - finfo.volume = finfo.i.volNumber; - error = -EACCES; - inode = ncp_iget(dir->i_sb, &finfo); - - if (inode) { - ncp_new_dentry(dentry); -add_entry: - d_add(dentry, inode); - error = 0; + if (!res) { + /* + * Entry found; create an inode for it. + */ + finfo.opened = 0; + finfo.ino = iunique(dir->i_sb, 2); + finfo.volume = finfo.i.volNumber; + inode = ncp_iget(dir->i_sb, &finfo); + if (unlikely(!inode)) + inode = ERR_PTR(-EACCES); + else + ncp_new_dentry(dentry); } - -finished: - ncp_vdbg("result=%d\n", error); - return ERR_PTR(error); + return d_splice_alias(inode, dentry); } /* diff --git a/drivers/vfio/virqfd.c b/drivers/vfio/virqfd.c index 085700f1be10..2a1be859ee71 100644 --- a/drivers/vfio/virqfd.c +++ b/drivers/vfio/virqfd.c @@ -166,7 +166,7 @@ int vfio_virqfd_enable(void *opaque, init_waitqueue_func_entry(&virqfd->wait, virqfd_wakeup); init_poll_funcptr(&virqfd->pt, virqfd_ptable_queue_proc); - events = irqfd.file->f_op->poll(irqfd.file, &virqfd->pt); + events = vfs_poll(irqfd.file, &virqfd->pt); /* * Check if there was an event already pending on the eventfd diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index f0be5f35ab28..895eaa25807c 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -208,7 +208,7 @@ int vhost_poll_start(struct vhost_poll *poll, struct file *file) if (poll->wqh) return 0; - mask = file->f_op->poll(file, &poll->table); + mask = vfs_poll(file, &poll->table); if (mask) vhost_poll_wakeup(&poll->wait, 0, 0, poll_to_key(mask)); if (mask & EPOLLERR) { diff --git a/drivers/w1/w1_io.c b/drivers/w1/w1_io.c index 075d120e7b88..0364d3329c52 100644 --- a/drivers/w1/w1_io.c +++ b/drivers/w1/w1_io.c @@ -194,6 +194,7 @@ static u8 w1_read_bit(struct w1_master *dev) * bit 0 = id_bit * bit 1 = comp_bit * bit 2 = dir_taken + * * If both bits 0 & 1 are set, the search should be restarted. * * Return: bit fields - see above diff --git a/drivers/zorro/zorro.c b/drivers/zorro/zorro.c index 47728477297e..67fa900572a9 100644 --- a/drivers/zorro/zorro.c +++ b/drivers/zorro/zorro.c @@ -101,6 +101,7 @@ static void __init mark_region(unsigned long start, unsigned long end, end = end > Z2RAM_END ? Z2RAM_SIZE : end-Z2RAM_START; while (start < end) { u32 chunk = start>>Z2RAM_CHUNKSHIFT; + if (flag) set_bit(chunk, zorro_unused_z2ram); else @@ -117,6 +118,7 @@ static struct resource __init *zorro_find_parent_resource( for (i = 0; i < bridge->num_resources; i++) { struct resource *r = &bridge->resource[i]; + if (zorro_resource_start(z) >= r->start && zorro_resource_end(z) <= r->end) return r; @@ -168,6 +170,7 @@ static int __init amiga_zorro_probe(struct platform_device *pdev) if (z->id == ZORRO_PROD_GVP_EPC_BASE) { /* GVP quirk */ unsigned long magic = zi->boardaddr + 0x8000; + z->id |= *(u16 *)ZTWO_VADDR(magic) & GVP_PRODMASK; } z->slotaddr = zi->slotaddr; |