diff options
Diffstat (limited to 'drivers/char')
38 files changed, 422 insertions, 2041 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index fa3243d..1421997 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -522,16 +522,10 @@ config HPET_MMAP If you say Y here, user applications will be able to mmap the HPET registers. -config HPET_MMAP_DEFAULT - bool "Enable HPET MMAP access by default" - default y - depends on HPET_MMAP - help In some hardware implementations, the page containing HPET registers may also contain other things that shouldn't be - exposed to the user. This option selects the default (if - kernel parameter hpet_mmap is not set) user access to the - registers for applications that require it. + exposed to the user. If this applies to your hardware, + say N here. config HANGCHECK_TIMER tristate "Hangcheck timer" diff --git a/drivers/char/bsr.c b/drivers/char/bsr.c index 8fedbc2..0671e45 100644 --- a/drivers/char/bsr.c +++ b/drivers/char/bsr.c @@ -21,7 +21,6 @@ #include <linux/kernel.h> #include <linux/of.h> -#include <linux/of_address.h> #include <linux/of_device.h> #include <linux/of_platform.h> #include <linux/fs.h> diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 5d9c31d..448ce5e 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -367,29 +367,12 @@ static unsigned int hpet_poll(struct file *file, poll_table * wait) return 0; } -#ifdef CONFIG_HPET_MMAP -#ifdef CONFIG_HPET_MMAP_DEFAULT -static int hpet_mmap_enabled = 1; -#else -static int hpet_mmap_enabled = 0; -#endif - -static __init int hpet_mmap_enable(char *str) -{ - get_option(&str, &hpet_mmap_enabled); - pr_info("HPET mmap %s\n", hpet_mmap_enabled ? "enabled" : "disabled"); - return 1; -} -__setup("hpet_mmap", hpet_mmap_enable); - static int hpet_mmap(struct file *file, struct vm_area_struct *vma) { +#ifdef CONFIG_HPET_MMAP struct hpet_dev *devp; unsigned long addr; - if (!hpet_mmap_enabled) - return -EACCES; - devp = file->private_data; addr = devp->hd_hpets->hp_hpet_phys; @@ -398,13 +381,10 @@ static int hpet_mmap(struct file *file, struct vm_area_struct *vma) vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); return vm_iomap_memory(vma, addr, PAGE_SIZE); -} #else -static int hpet_mmap(struct file *file, struct vm_area_struct *vma) -{ return -ENOSYS; -} #endif +} static int hpet_fasync(int fd, struct file *file, int on) { @@ -506,7 +486,8 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp) } sprintf(devp->hd_name, "hpet%d", (int)(devp - hpetp->hp_dev)); - irq_flags = devp->hd_flags & HPET_SHARED_IRQ ? IRQF_SHARED : 0; + irq_flags = devp->hd_flags & HPET_SHARED_IRQ + ? IRQF_SHARED : IRQF_DISABLED; if (request_irq(irq, hpet_interrupt, irq_flags, devp->hd_name, (void *)devp)) { printk(KERN_ERR "hpet: IRQ %d is not free\n", irq); @@ -990,6 +971,8 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data) struct acpi_resource_fixed_memory32 *fixmem32; fixmem32 = &res->data.fixed_memory32; + if (!fixmem32) + return AE_NO_MEMORY; hdp->hd_phys_address = fixmem32->address; hdp->hd_address = ioremap(fixmem32->address, diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 2f2b084..0aa9d91 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -165,19 +165,6 @@ config HW_RANDOM_OMAP If unsure, say Y. -config HW_RANDOM_OMAP3_ROM - tristate "OMAP3 ROM Random Number Generator support" - depends on HW_RANDOM && ARCH_OMAP3 - default HW_RANDOM - ---help--- - This driver provides kernel-side support for the Random Number - Generator hardware found on OMAP34xx processors. - - To compile this driver as a module, choose M here: the - module will be called omap3-rom-rng. - - If unsure, say Y. - config HW_RANDOM_OCTEON tristate "Octeon Random Number Generator support" depends on HW_RANDOM && CAVIUM_OCTEON_SOC @@ -303,19 +290,6 @@ config HW_RANDOM_PSERIES If unsure, say Y. -config HW_RANDOM_POWERNV - tristate "PowerNV Random Number Generator support" - depends on HW_RANDOM && PPC_POWERNV - default HW_RANDOM - ---help--- - This is the driver for Random Number Generator hardware found - in POWER7+ and above machines for PowerNV platform. - - To compile this driver as a module, choose M here: the - module will be called powernv-rng. - - If unsure, say Y. - config HW_RANDOM_EXYNOS tristate "EXYNOS HW random number generator support" depends on HW_RANDOM && HAS_IOMEM && HAVE_CLK @@ -340,15 +314,3 @@ config HW_RANDOM_TPM module will be called tpm-rng. If unsure, say Y. - -config HW_RANDOM_MSM - tristate "Qualcomm MSM Random Number Generator support" - depends on HW_RANDOM && ARCH_MSM - ---help--- - This driver provides kernel-side support for the Random Number - Generator hardware found on Qualcomm MSM SoCs. - - To compile this driver as a module, choose M here. the - module will be called msm-rng. - - If unsure, say Y. diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile index 3ae7755..bed467c 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile @@ -15,7 +15,6 @@ n2-rng-y := n2-drv.o n2-asm.o obj-$(CONFIG_HW_RANDOM_VIA) += via-rng.o obj-$(CONFIG_HW_RANDOM_IXP4XX) += ixp4xx-rng.o obj-$(CONFIG_HW_RANDOM_OMAP) += omap-rng.o -obj-$(CONFIG_HW_RANDOM_OMAP3_ROM) += omap3-rom-rng.o obj-$(CONFIG_HW_RANDOM_PASEMI) += pasemi-rng.o obj-$(CONFIG_HW_RANDOM_VIRTIO) += virtio-rng.o obj-$(CONFIG_HW_RANDOM_TX4939) += tx4939-rng.o @@ -25,8 +24,6 @@ obj-$(CONFIG_HW_RANDOM_NOMADIK) += nomadik-rng.o obj-$(CONFIG_HW_RANDOM_PICOXCELL) += picoxcell-rng.o obj-$(CONFIG_HW_RANDOM_PPC4XX) += ppc4xx-rng.o obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o -obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o obj-$(CONFIG_HW_RANDOM_EXYNOS) += exynos-rng.o obj-$(CONFIG_HW_RANDOM_TPM) += tpm-rng.o obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o -obj-$(CONFIG_HW_RANDOM_MSM) += msm-rng.o diff --git a/drivers/char/hw_random/msm-rng.c b/drivers/char/hw_random/msm-rng.c deleted file mode 100644 index 148521e..0000000 --- a/drivers/char/hw_random/msm-rng.c +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright (c) 2011-2013, The Linux Foundation. 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 version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ -#include <linux/clk.h> -#include <linux/err.h> -#include <linux/hw_random.h> -#include <linux/io.h> -#include <linux/module.h> -#include <linux/of.h> -#include <linux/platform_device.h> - -/* Device specific register offsets */ -#define PRNG_DATA_OUT 0x0000 -#define PRNG_STATUS 0x0004 -#define PRNG_LFSR_CFG 0x0100 -#define PRNG_CONFIG 0x0104 - -/* Device specific register masks and config values */ -#define PRNG_LFSR_CFG_MASK 0x0000ffff -#define PRNG_LFSR_CFG_CLOCKS 0x0000dddd -#define PRNG_CONFIG_HW_ENABLE BIT(1) -#define PRNG_STATUS_DATA_AVAIL BIT(0) - -#define MAX_HW_FIFO_DEPTH 16 -#define MAX_HW_FIFO_SIZE (MAX_HW_FIFO_DEPTH * 4) -#define WORD_SZ 4 - -struct msm_rng { - void __iomem *base; - struct clk *clk; - struct hwrng hwrng; -}; - -#define to_msm_rng(p) container_of(p, struct msm_rng, hwrng) - -static int msm_rng_enable(struct hwrng *hwrng, int enable) -{ - struct msm_rng *rng = to_msm_rng(hwrng); - u32 val; - int ret; - - ret = clk_prepare_enable(rng->clk); - if (ret) - return ret; - - if (enable) { - /* Enable PRNG only if it is not already enabled */ - val = readl_relaxed(rng->base + PRNG_CONFIG); - if (val & PRNG_CONFIG_HW_ENABLE) - goto already_enabled; - - val = readl_relaxed(rng->base + PRNG_LFSR_CFG); - val &= ~PRNG_LFSR_CFG_MASK; - val |= PRNG_LFSR_CFG_CLOCKS; - writel(val, rng->base + PRNG_LFSR_CFG); - - val = readl_relaxed(rng->base + PRNG_CONFIG); - val |= PRNG_CONFIG_HW_ENABLE; - writel(val, rng->base + PRNG_CONFIG); - } else { - val = readl_relaxed(rng->base + PRNG_CONFIG); - val &= ~PRNG_CONFIG_HW_ENABLE; - writel(val, rng->base + PRNG_CONFIG); - } - -already_enabled: - clk_disable_unprepare(rng->clk); - return 0; -} - -static int msm_rng_read(struct hwrng *hwrng, void *data, size_t max, bool wait) -{ - struct msm_rng *rng = to_msm_rng(hwrng); - size_t currsize = 0; - u32 *retdata = data; - size_t maxsize; - int ret; - u32 val; - - /* calculate max size bytes to transfer back to caller */ - maxsize = min_t(size_t, MAX_HW_FIFO_SIZE, max); - - /* no room for word data */ - if (maxsize < WORD_SZ) - return 0; - - ret = clk_prepare_enable(rng->clk); - if (ret) - return ret; - - /* read random data from hardware */ - do { - val = readl_relaxed(rng->base + PRNG_STATUS); - if (!(val & PRNG_STATUS_DATA_AVAIL)) - break; - - val = readl_relaxed(rng->base + PRNG_DATA_OUT); - if (!val) - break; - - *retdata++ = val; - currsize += WORD_SZ; - - /* make sure we stay on 32bit boundary */ - if ((maxsize - currsize) < WORD_SZ) - break; - } while (currsize < maxsize); - - clk_disable_unprepare(rng->clk); - - return currsize; -} - -static int msm_rng_init(struct hwrng *hwrng) -{ - return msm_rng_enable(hwrng, 1); -} - -static void msm_rng_cleanup(struct hwrng *hwrng) -{ - msm_rng_enable(hwrng, 0); -} - -static int msm_rng_probe(struct platform_device *pdev) -{ - struct resource *res; - struct msm_rng *rng; - int ret; - - rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL); - if (!rng) - return -ENOMEM; - - platform_set_drvdata(pdev, rng); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - rng->base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(rng->base)) - return PTR_ERR(rng->base); - - rng->clk = devm_clk_get(&pdev->dev, "core"); - if (IS_ERR(rng->clk)) - return PTR_ERR(rng->clk); - - rng->hwrng.name = KBUILD_MODNAME, - rng->hwrng.init = msm_rng_init, - rng->hwrng.cleanup = msm_rng_cleanup, - rng->hwrng.read = msm_rng_read, - - ret = hwrng_register(&rng->hwrng); - if (ret) { - dev_err(&pdev->dev, "failed to register hwrng\n"); - return ret; - } - - return 0; -} - -static int msm_rng_remove(struct platform_device *pdev) -{ - struct msm_rng *rng = platform_get_drvdata(pdev); - - hwrng_unregister(&rng->hwrng); - return 0; -} - -static const struct of_device_id msm_rng_of_match[] = { - { .compatible = "qcom,prng", }, - {} -}; -MODULE_DEVICE_TABLE(of, msm_rng_of_match); - -static struct platform_driver msm_rng_driver = { - .probe = msm_rng_probe, - .remove = msm_rng_remove, - .driver = { - .name = KBUILD_MODNAME, - .owner = THIS_MODULE, - .of_match_table = of_match_ptr(msm_rng_of_match), - } -}; -module_platform_driver(msm_rng_driver); - -MODULE_ALIAS("platform:" KBUILD_MODNAME); -MODULE_AUTHOR("The Linux Foundation"); -MODULE_DESCRIPTION("Qualcomm MSM random number generator driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/char/hw_random/omap3-rom-rng.c b/drivers/char/hw_random/omap3-rom-rng.c deleted file mode 100644 index c853e9e..0000000 --- a/drivers/char/hw_random/omap3-rom-rng.c +++ /dev/null @@ -1,141 +0,0 @@ -/* - * omap3-rom-rng.c - RNG driver for TI OMAP3 CPU family - * - * Copyright (C) 2009 Nokia Corporation - * Author: Juha Yrjola <juha.yrjola@solidboot.com> - * - * Copyright (C) 2013 Pali Rohár <pali.rohar@gmail.com> - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/random.h> -#include <linux/hw_random.h> -#include <linux/timer.h> -#include <linux/clk.h> -#include <linux/err.h> -#include <linux/platform_device.h> - -#define RNG_RESET 0x01 -#define RNG_GEN_PRNG_HW_INIT 0x02 -#define RNG_GEN_HW 0x08 - -/* param1: ptr, param2: count, param3: flag */ -static u32 (*omap3_rom_rng_call)(u32, u32, u32); - -static struct timer_list idle_timer; -static int rng_idle; -static struct clk *rng_clk; - -static void omap3_rom_rng_idle(unsigned long data) -{ - int r; - - r = omap3_rom_rng_call(0, 0, RNG_RESET); - if (r != 0) { - pr_err("reset failed: %d\n", r); - return; - } - clk_disable_unprepare(rng_clk); - rng_idle = 1; -} - -static int omap3_rom_rng_get_random(void *buf, unsigned int count) -{ - u32 r; - u32 ptr; - - del_timer_sync(&idle_timer); - if (rng_idle) { - clk_prepare_enable(rng_clk); - r = omap3_rom_rng_call(0, 0, RNG_GEN_PRNG_HW_INIT); - if (r != 0) { - clk_disable_unprepare(rng_clk); - pr_err("HW init failed: %d\n", r); - return -EIO; - } - rng_idle = 0; - } - - ptr = virt_to_phys(buf); - r = omap3_rom_rng_call(ptr, count, RNG_GEN_HW); - mod_timer(&idle_timer, jiffies + msecs_to_jiffies(500)); - if (r != 0) - return -EINVAL; - return 0; -} - -static int omap3_rom_rng_data_present(struct hwrng *rng, int wait) -{ - return 1; -} - -static int omap3_rom_rng_data_read(struct hwrng *rng, u32 *data) -{ - int r; - - r = omap3_rom_rng_get_random(data, 4); - if (r < 0) - return r; - return 4; -} - -static struct hwrng omap3_rom_rng_ops = { - .name = "omap3-rom", - .data_present = omap3_rom_rng_data_present, - .data_read = omap3_rom_rng_data_read, -}; - -static int omap3_rom_rng_probe(struct platform_device *pdev) -{ - pr_info("initializing\n"); - - omap3_rom_rng_call = pdev->dev.platform_data; - if (!omap3_rom_rng_call) { - pr_err("omap3_rom_rng_call is NULL\n"); - return -EINVAL; - } - - setup_timer(&idle_timer, omap3_rom_rng_idle, 0); - rng_clk = clk_get(&pdev->dev, "ick"); - if (IS_ERR(rng_clk)) { - pr_err("unable to get RNG clock\n"); - return PTR_ERR(rng_clk); - } - - /* Leave the RNG in reset state. */ - clk_prepare_enable(rng_clk); - omap3_rom_rng_idle(0); - - return hwrng_register(&omap3_rom_rng_ops); -} - -static int omap3_rom_rng_remove(struct platform_device *pdev) -{ - hwrng_unregister(&omap3_rom_rng_ops); - clk_disable_unprepare(rng_clk); - clk_put(rng_clk); - return 0; -} - -static struct platform_driver omap3_rom_rng_driver = { - .driver = { - .name = "omap3-rom-rng", - .owner = THIS_MODULE, - }, - .probe = omap3_rom_rng_probe, - .remove = omap3_rom_rng_remove, -}; - -module_platform_driver(omap3_rom_rng_driver); - -MODULE_ALIAS("platform:omap3-rom-rng"); -MODULE_AUTHOR("Juha Yrjola"); -MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/char/hw_random/pasemi-rng.c b/drivers/char/hw_random/pasemi-rng.c index c66279b..c6df5b2 100644 --- a/drivers/char/hw_random/pasemi-rng.c +++ b/drivers/char/hw_random/pasemi-rng.c @@ -24,7 +24,6 @@ #include <linux/platform_device.h> #include <linux/hw_random.h> #include <linux/delay.h> -#include <linux/of_address.h> #include <linux/of_platform.h> #include <asm/io.h> diff --git a/drivers/char/hw_random/powernv-rng.c b/drivers/char/hw_random/powernv-rng.c deleted file mode 100644 index 3f4f632..0000000 --- a/drivers/char/hw_random/powernv-rng.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2013 Michael Ellerman, Guo Chao, IBM Corp. - * - * 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. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/platform_device.h> -#include <linux/random.h> -#include <linux/hw_random.h> - -static int powernv_rng_read(struct hwrng *rng, void *data, size_t max, bool wait) -{ - unsigned long *buf; - int i, len; - - /* We rely on rng_buffer_size() being >= sizeof(unsigned long) */ - len = max / sizeof(unsigned long); - - buf = (unsigned long *)data; - - for (i = 0; i < len; i++) - powernv_get_random_long(buf++); - - return len * sizeof(unsigned long); -} - -static struct hwrng powernv_hwrng = { - .name = "powernv-rng", - .read = powernv_rng_read, -}; - -static int powernv_rng_remove(struct platform_device *pdev) -{ - hwrng_unregister(&powernv_hwrng); - - return 0; -} - -static int powernv_rng_probe(struct platform_device *pdev) -{ - int rc; - - rc = hwrng_register(&powernv_hwrng); - if (rc) { - /* We only register one device, ignore any others */ - if (rc == -EEXIST) - rc = -ENODEV; - - return rc; - } - - pr_info("Registered powernv hwrng.\n"); - - return 0; -} - -static struct of_device_id powernv_rng_match[] = { - { .compatible = "ibm,power-rng",}, - {}, -}; -MODULE_DEVICE_TABLE(of, powernv_rng_match); - -static struct platform_driver powernv_rng_driver = { - .driver = { - .name = "powernv_rng", - .of_match_table = powernv_rng_match, - }, - .probe = powernv_rng_probe, - .remove = powernv_rng_remove, -}; -module_platform_driver(powernv_rng_driver); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Bare metal HWRNG driver for POWER7+ and above"); diff --git a/drivers/char/hw_random/ppc4xx-rng.c b/drivers/char/hw_random/ppc4xx-rng.c index 521f76b..732c330 100644 --- a/drivers/char/hw_random/ppc4xx-rng.c +++ b/drivers/char/hw_random/ppc4xx-rng.c @@ -13,7 +13,6 @@ #include <linux/platform_device.h> #include <linux/hw_random.h> #include <linux/delay.h> -#include <linux/of_address.h> #include <linux/of_platform.h> #include <asm/io.h> diff --git a/drivers/char/hw_random/pseries-rng.c b/drivers/char/hw_random/pseries-rng.c index ab7ffde..5f11979 100644 --- a/drivers/char/hw_random/pseries-rng.c +++ b/drivers/char/hw_random/pseries-rng.c @@ -17,25 +17,18 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/kernel.h> #include <linux/module.h> #include <linux/hw_random.h> #include <asm/vio.h> +#define MODULE_NAME "pseries-rng" static int pseries_rng_data_read(struct hwrng *rng, u32 *data) { - int rc; - - rc = plpar_hcall(H_RANDOM, (unsigned long *)data); - if (rc != H_SUCCESS) { - pr_err_ratelimited("H_RANDOM call failed %d\n", rc); - return -EIO; + if (plpar_hcall(H_RANDOM, (unsigned long *)data) != H_SUCCESS) { + printk(KERN_ERR "pseries rng hcall error\n"); + return 0; } - - /* The hypervisor interface returns 64 bits */ return 8; } @@ -54,7 +47,7 @@ static unsigned long pseries_rng_get_desired_dma(struct vio_dev *vdev) }; static struct hwrng pseries_rng = { - .name = KBUILD_MODNAME, + .name = MODULE_NAME, .data_read = pseries_rng_data_read, }; @@ -77,7 +70,7 @@ static struct vio_device_id pseries_rng_driver_ids[] = { MODULE_DEVICE_TABLE(vio, pseries_rng_driver_ids); static struct vio_driver pseries_rng_driver = { - .name = KBUILD_MODNAME, + .name = MODULE_NAME, .probe = pseries_rng_probe, .remove = pseries_rng_remove, .get_desired_dma = pseries_rng_get_desired_dma, diff --git a/drivers/char/hw_random/timeriomem-rng.c b/drivers/char/hw_random/timeriomem-rng.c index 73ce739..d2120ba 100644 --- a/drivers/char/hw_random/timeriomem-rng.c +++ b/drivers/char/hw_random/timeriomem-rng.c @@ -79,7 +79,7 @@ static int timeriomem_rng_data_read(struct hwrng *rng, u32 *data) priv->expires = cur + delay; priv->present = 0; - reinit_completion(&priv->completion); + INIT_COMPLETION(priv->completion); mod_timer(&priv->timer, priv->expires); return 4; diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c index de5a6dc..e737772 100644 --- a/drivers/char/hw_random/via-rng.c +++ b/drivers/char/hw_random/via-rng.c @@ -221,7 +221,7 @@ static void __exit mod_exit(void) module_init(mod_init); module_exit(mod_exit); -static struct x86_cpu_id __maybe_unused via_rng_cpu_id[] = { +static struct x86_cpu_id via_rng_cpu_id[] = { X86_FEATURE_MATCH(X86_FEATURE_XSTORE), {} }; diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c index c12398d..ef46a9c 100644 --- a/drivers/char/hw_random/virtio-rng.c +++ b/drivers/char/hw_random/virtio-rng.c @@ -133,7 +133,7 @@ static void virtrng_remove(struct virtio_device *vdev) remove_common(vdev); } -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_PM static int virtrng_freeze(struct virtio_device *vdev) { remove_common(vdev); @@ -157,7 +157,7 @@ static struct virtio_driver virtio_rng_driver = { .id_table = id_table, .probe = virtrng_probe, .remove = virtrng_remove, -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_PM .freeze = virtrng_freeze, .restore = virtrng_restore, #endif diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c index e6939e1..40cc0cf2 100644 --- a/drivers/char/i8k.c +++ b/drivers/char/i8k.c @@ -664,13 +664,6 @@ static struct dmi_system_id __initdata i8k_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Vostro"), }, }, - { - .ident = "Dell XPS421", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "XPS L421X"), - }, - }, { } }; diff --git a/drivers/char/misc.c b/drivers/char/misc.c index ffa97d2..190d442 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -114,7 +114,7 @@ static int misc_open(struct inode * inode, struct file * file) int minor = iminor(inode); struct miscdevice *c; int err = -ENODEV; - const struct file_operations *new_fops = NULL; + const struct file_operations *old_fops, *new_fops = NULL; mutex_lock(&misc_mtx); @@ -141,11 +141,17 @@ static int misc_open(struct inode * inode, struct file * file) } err = 0; - replace_fops(file, new_fops); + old_fops = file->f_op; + file->f_op = new_fops; if (file->f_op->open) { file->private_data = c; - err = file->f_op->open(inode,file); + err=file->f_op->open(inode,file); + if (err) { + fops_put(file->f_op); + file->f_op = fops_get(old_fops); + } } + fops_put(old_fops); fail: mutex_unlock(&misc_mtx); return err; @@ -187,8 +193,8 @@ int misc_register(struct miscdevice * misc) if (misc->minor == MISC_DYNAMIC_MINOR) { int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS); if (i >= DYNAMIC_MINORS) { - err = -EBUSY; - goto out; + mutex_unlock(&misc_mtx); + return -EBUSY; } misc->minor = DYNAMIC_MINORS - i - 1; set_bit(i, misc_minors); @@ -197,8 +203,8 @@ int misc_register(struct miscdevice * misc) list_for_each_entry(c, &misc_list, list) { if (c->minor == misc->minor) { - err = -EBUSY; - goto out; + mutex_unlock(&misc_mtx); + return -EBUSY; } } } diff --git a/drivers/char/nwbutton.c b/drivers/char/nwbutton.c index 1fd00dc..cfdfe49 100644 --- a/drivers/char/nwbutton.c +++ b/drivers/char/nwbutton.c @@ -220,7 +220,7 @@ static int __init nwbutton_init(void) return -EBUSY; } - if (request_irq (IRQ_NETWINDER_BUTTON, button_handler, 0, + if (request_irq (IRQ_NETWINDER_BUTTON, button_handler, IRQF_DISABLED, "nwbutton", NULL)) { printk (KERN_WARNING "nwbutton: IRQ %d is not free.\n", IRQ_NETWINDER_BUTTON); diff --git a/drivers/char/random.c b/drivers/char/random.c index 429b75b..7a744d3 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -255,7 +255,6 @@ #include <linux/fips.h> #include <linux/ptrace.h> #include <linux/kmemcheck.h> -#include <linux/workqueue.h> #include <linux/irq.h> #include <asm/processor.h> @@ -270,28 +269,14 @@ /* * Configuration information */ -#define INPUT_POOL_SHIFT 12 -#define INPUT_POOL_WORDS (1 << (INPUT_POOL_SHIFT-5)) -#define OUTPUT_POOL_SHIFT 10 -#define OUTPUT_POOL_WORDS (1 << (OUTPUT_POOL_SHIFT-5)) -#define SEC_XFER_SIZE 512 -#define EXTRACT_SIZE 10 - -#define DEBUG_RANDOM_BOOT 0 +#define INPUT_POOL_WORDS 128 +#define OUTPUT_POOL_WORDS 32 +#define SEC_XFER_SIZE 512 +#define EXTRACT_SIZE 10 #define LONGS(x) (((x) + sizeof(unsigned long) - 1)/sizeof(unsigned long)) /* - * To allow fractional bits to be tracked, the entropy_count field is - * denominated in units of 1/8th bits. - * - * 2*(ENTROPY_SHIFT + log2(poolbits)) must <= 31, or the multiply in - * credit_entropy_bits() needs to be 64 bits wide. - */ -#define ENTROPY_SHIFT 3 -#define ENTROPY_BITS(r) ((r)->entropy_count >> ENTROPY_SHIFT) - -/* * The minimum number of bits of entropy before we wake up a read on * /dev/random. Should be enough to do a significant reseed. */ @@ -302,100 +287,108 @@ static int random_read_wakeup_thresh = 64; * should wake up processes which are selecting or polling on write * access to /dev/random. */ -static int random_write_wakeup_thresh = 28 * OUTPUT_POOL_WORDS; +static int random_write_wakeup_thresh = 128; /* - * The minimum number of seconds between urandom pool resending. We - * do this to limit the amount of entropy that can be drained from the - * input pool even if there are heavy demands on /dev/urandom. + * When the input pool goes over trickle_thresh, start dropping most + * samples to avoid wasting CPU time and reduce lock contention. */ -static int random_min_urandom_seed = 60; + +static int trickle_thresh __read_mostly = INPUT_POOL_WORDS * 28; + +static DEFINE_PER_CPU(int, trickle_count); /* - * Originally, we used a primitive polynomial of degree .poolwords - * over GF(2). The taps for various sizes are defined below. They - * were chosen to be evenly spaced except for the last tap, which is 1 - * to get the twisting happening as fast as possible. - * - * For the purposes of better mixing, we use the CRC-32 polynomial as - * well to make a (modified) twisted Generalized Feedback Shift - * Register. (See M. Matsumoto & Y. Kurita, 1992. Twisted GFSR - * generators. ACM Transactions on Modeling and Computer Simulation - * 2(3):179-194. Also see M. Matsumoto & Y. Kurita, 1994. Twisted - * GFSR generators II. ACM Transactions on Mdeling and Computer - * Simulation 4:254-266) - * - * Thanks to Colin Plumb for suggesting this. - * - * The mixing operation is much less sensitive than the output hash, - * where we use SHA-1. All that we want of mixing operation is that - * it be a good non-cryptographic hash; i.e. it not produce collisions - * when fed "random" data of the sort we expect to see. As long as - * the pool state differs for different inputs, we have preserved the - * input entropy and done a good job. The fact that an intelligent - * attacker can construct inputs that will produce controlled - * alterations to the pool's state is not important because we don't - * consider such inputs to contribute any randomness. The only - * property we need with respect to them is that the attacker can't - * increase his/her knowledge of the pool's state. Since all - * additions are reversible (knowing the final state and the input, - * you can reconstruct the initial state), if an attacker has any - * uncertainty about the initial state, he/she can only shuffle that - * uncertainty about, but never cause any collisions (which would - * decrease the uncertainty). - * - * Our mixing functions were analyzed by Lacharme, Roeck, Strubel, and - * Videau in their paper, "The Linux Pseudorandom Number Generator - * Revisited" (see: http://eprint.iacr.org/2012/251.pdf). In their - * paper, they point out that we are not using a true Twisted GFSR, - * since Matsumoto & Kurita used a trinomial feedback polynomial (that - * is, with only three taps, instead of the six that we are using). - * As a result, the resulting polynomial is neither primitive nor - * irreducible, and hence does not have a maximal period over - * GF(2**32). They suggest a slight change to the generator - * polynomial which improves the resulting TGFSR polynomial to be - * irreducible, which we have made here. + * A pool of size .poolwords is stirred with a primitive polynomial + * of degree .poolwords over GF(2). The taps for various sizes are + * defined below. They are chosen to be evenly spaced (minimum RMS + * distance from evenly spaced; the numbers in the comments are a + * scaled squared error sum) except for the last tap, which is 1 to + * get the twisting happening as fast as possible. */ static struct poolinfo { - int poolbitshift, poolwords, poolbytes, poolbits, poolfracbits; -#define S(x) ilog2(x)+5, (x), (x)*4, (x)*32, (x) << (ENTROPY_SHIFT+5) + int poolwords; int tap1, tap2, tap3, tap4, tap5; } poolinfo_table[] = { - /* was: x^128 + x^103 + x^76 + x^51 +x^25 + x + 1 */ - /* x^128 + x^104 + x^76 + x^51 +x^25 + x + 1 */ - { S(128), 104, 76, 51, 25, 1 }, - /* was: x^32 + x^26 + x^20 + x^14 + x^7 + x + 1 */ - /* x^32 + x^26 + x^19 + x^14 + x^7 + x + 1 */ - { S(32), 26, 19, 14, 7, 1 }, + /* x^128 + x^103 + x^76 + x^51 +x^25 + x + 1 -- 105 */ + { 128, 103, 76, 51, 25, 1 }, + /* x^32 + x^26 + x^20 + x^14 + x^7 + x + 1 -- 15 */ + { 32, 26, 20, 14, 7, 1 }, #if 0 /* x^2048 + x^1638 + x^1231 + x^819 + x^411 + x + 1 -- 115 */ - { S(2048), 1638, 1231, 819, 411, 1 }, + { 2048, 1638, 1231, 819, 411, 1 }, /* x^1024 + x^817 + x^615 + x^412 + x^204 + x + 1 -- 290 */ - { S(1024), 817, 615, 412, 204, 1 }, + { 1024, 817, 615, 412, 204, 1 }, /* x^1024 + x^819 + x^616 + x^410 + x^207 + x^2 + 1 -- 115 */ - { S(1024), 819, 616, 410, 207, 2 }, + { 1024, 819, 616, 410, 207, 2 }, /* x^512 + x^411 + x^308 + x^208 + x^104 + x + 1 -- 225 */ - { S(512), 411, 308, 208, 104, 1 }, + { 512, 411, 308, 208, 104, 1 }, /* x^512 + x^409 + x^307 + x^206 + x^102 + x^2 + 1 -- 95 */ - { S(512), 409, 307, 206, 102, 2 }, + { 512, 409, 307, 206, 102, 2 }, /* x^512 + x^409 + x^309 + x^205 + x^103 + x^2 + 1 -- 95 */ - { S(512), 409, 309, 205, 103, 2 }, + { 512, 409, 309, 205, 103, 2 }, /* x^256 + x^205 + x^155 + x^101 + x^52 + x + 1 -- 125 */ - { S(256), 205, 155, 101, 52, 1 }, + { 256, 205, 155, 101, 52, 1 }, /* x^128 + x^103 + x^78 + x^51 + x^27 + x^2 + 1 -- 70 */ - { S(128), 103, 78, 51, 27, 2 }, + { 128, 103, 78, 51, 27, 2 }, /* x^64 + x^52 + x^39 + x^26 + x^14 + x + 1 -- 15 */ - { S(64), 52, 39, 26, 14, 1 }, + { 64, 52, 39, 26, 14, 1 }, #endif }; +#define POOLBITS poolwords*32 +#define POOLBYTES poolwords*4 + +/* + * For the purposes of better mixing, we use the CRC-32 polynomial as + * well to make a twisted Generalized Feedback Shift Reigster + * + * (See M. Matsumoto & Y. Kurita, 1992. Twisted GFSR generators. ACM + * Transactions on Modeling and Computer Simulation 2(3):179-194. + * Also see M. Matsumoto & Y. Kurita, 1994. Twisted GFSR generators + * II. ACM Transactions on Mdeling and Computer Simulation 4:254-266) + * + * Thanks to Colin Plumb for suggesting this. + * + * We have not analyzed the resultant polynomial to prove it primitive; + * in fact it almost certainly isn't. Nonetheless, the irreducible factors + * of a random large-degree polynomial over GF(2) are more than large enough + * that periodicity is not a concern. + * + * The input hash is much less sensitive than the output hash. All + * that we want of it is that it be a good non-cryptographic hash; + * i.e. it not produce collisions when fed "random" data of the sort + * we expect to see. As long as the pool state differs for different + * inputs, we have preserved the input entropy and done a good job. + * The fact that an intelligent attacker can construct inputs that + * will produce controlled alterations to the pool's state is not + * important because we don't consider such inputs to contribute any + * randomness. The only property we need with respect to them is that + * the attacker can't increase his/her knowledge of the pool's state. + * Since all additions are reversible (knowing the final state and the + * input, you can reconstruct the initial state), if an attacker has + * any uncertainty about the initial state, he/she can only shuffle + * that uncertainty about, but never cause any collisions (which would + * decrease the uncertainty). + * + * The chosen system lets the state of the pool be (essentially) the input + * modulo the generator polymnomial. Now, for random primitive polynomials, + * this is a universal class of hash functions, meaning that the chance + * of a collision is limited by the attacker's knowledge of the generator + * polynomail, so if it is chosen at random, an attacker can never force + * a collision. Here, we use a fixed polynomial, but we *can* assume that + * ###--> it is unknown to the processes generating the input entropy. <-### + * Because of this important property, this is a good, collision-resistant + * hash; hash collisions will occur no more often than chance. + */ + /* * Static global variables */ @@ -403,6 +396,17 @@ static DECLARE_WAIT_QUEUE_HEAD(random_read_wait); static DECLARE_WAIT_QUEUE_HEAD(random_write_wait); static struct fasync_struct *fasync; +static bool debug; +module_param(debug, bool, 0644); +#define DEBUG_ENT(fmt, arg...) do { \ + if (debug) \ + printk(KERN_DEBUG "random %04d %04d %04d: " \ + fmt,\ + input_pool.entropy_count,\ + blocking_pool.entropy_count,\ + nonblocking_pool.entropy_count,\ + ## arg); } while (0) + /********************************************************************** * * OS independent entropy store. Here are the functions which handle @@ -413,26 +417,23 @@ static struct fasync_struct *fasync; struct entropy_store; struct entropy_store { /* read-only data: */ - const struct poolinfo *poolinfo; + struct poolinfo *poolinfo; __u32 *pool; const char *name; struct entropy_store *pull; - struct work_struct push_work; + int limit; /* read-write data: */ - unsigned long last_pulled; spinlock_t lock; - unsigned short add_ptr; - unsigned short input_rotate; + unsigned add_ptr; + unsigned input_rotate; int entropy_count; int entropy_total; unsigned int initialized:1; - unsigned int limit:1; - unsigned int last_data_init:1; + bool last_data_init; __u8 last_data[EXTRACT_SIZE]; }; -static void push_to_pool(struct work_struct *work); static __u32 input_pool_data[INPUT_POOL_WORDS]; static __u32 blocking_pool_data[OUTPUT_POOL_WORDS]; static __u32 nonblocking_pool_data[OUTPUT_POOL_WORDS]; @@ -451,9 +452,7 @@ static struct entropy_store blocking_pool = { .limit = 1, .pull = &input_pool, .lock = __SPIN_LOCK_UNLOCKED(blocking_pool.lock), - .pool = blocking_pool_data, - .push_work = __WORK_INITIALIZER(blocking_pool.push_work, - push_to_pool), + .pool = blocking_pool_data }; static struct entropy_store nonblocking_pool = { @@ -461,9 +460,7 @@ static struct entropy_store nonblocking_pool = { .name = "nonblocking", .pull = &input_pool, .lock = __SPIN_LOCK_UNLOCKED(nonblocking_pool.lock), - .pool = nonblocking_pool_data, - .push_work = __WORK_INITIALIZER(nonblocking_pool.push_work, - push_to_pool), + .pool = nonblocking_pool_data }; static __u32 const twist_table[8] = { @@ -501,7 +498,7 @@ static void _mix_pool_bytes(struct entropy_store *r, const void *in, /* mix one byte at a time to simplify size handling and churn faster */ while (nbytes--) { - w = rol32(*bytes++, input_rotate); + w = rol32(*bytes++, input_rotate & 31); i = (i - 1) & wordmask; /* XOR in the various taps */ @@ -521,7 +518,7 @@ static void _mix_pool_bytes(struct entropy_store *r, const void *in, * rotation, so that successive passes spread the * input bits across the pool evenly. */ - input_rotate = (input_rotate + (i ? 7 : 14)) & 31; + input_rotate += i ? 7 : 14; } ACCESS_ONCE(r->input_rotate) = input_rotate; @@ -564,151 +561,62 @@ struct fast_pool { * collector. It's hardcoded for an 128 bit pool and assumes that any * locks that might be needed are taken by the caller. */ -static void fast_mix(struct fast_pool *f, __u32 input[4]) +static void fast_mix(struct fast_pool *f, const void *in, int nbytes) { + const char *bytes = in; __u32 w; + unsigned i = f->count; unsigned input_rotate = f->rotate; - w = rol32(input[0], input_rotate) ^ f->pool[0] ^ f->pool[3]; - f->pool[0] = (w >> 3) ^ twist_table[w & 7]; - input_rotate = (input_rotate + 14) & 31; - w = rol32(input[1], input_rotate) ^ f->pool[1] ^ f->pool[0]; - f->pool[1] = (w >> 3) ^ twist_table[w & 7]; - input_rotate = (input_rotate + 7) & 31; - w = rol32(input[2], input_rotate) ^ f->pool[2] ^ f->pool[1]; - f->pool[2] = (w >> 3) ^ twist_table[w & 7]; - input_rotate = (input_rotate + 7) & 31; - w = rol32(input[3], input_rotate) ^ f->pool[3] ^ f->pool[2]; - f->pool[3] = (w >> 3) ^ twist_table[w & 7]; - input_rotate = (input_rotate + 7) & 31; - + while (nbytes--) { + w = rol32(*bytes++, input_rotate & 31) ^ f->pool[i & 3] ^ + f->pool[(i + 1) & 3]; + f->pool[i & 3] = (w >> 3) ^ twist_table[w & 7]; + input_rotate += (i++ & 3) ? 7 : 14; + } + f->count = i; f->rotate = input_rotate; - f->count++; } /* - * Credit (or debit) the entropy store with n bits of entropy. - * Use credit_entropy_bits_safe() if the value comes from userspace - * or otherwise should be checked for extreme values. + * Credit (or debit) the entropy store with n bits of entropy */ static void credit_entropy_bits(struct entropy_store *r, int nbits) { int entropy_count, orig; - const int pool_size = r->poolinfo->poolfracbits; - int nfrac = nbits << ENTROPY_SHIFT; if (!nbits) return; + DEBUG_ENT("added %d entropy credits to %s\n", nbits, r->name); retry: entropy_count = orig = ACCESS_ONCE(r->entropy_count); - if (nfrac < 0) { - /* Debit */ - entropy_count += nfrac; - } else { - /* - * Credit: we have to account for the possibility of - * overwriting already present entropy. Even in the - * ideal case of pure Shannon entropy, new contributions - * approach the full value asymptotically: - * - * entropy <- entropy + (pool_size - entropy) * - * (1 - exp(-add_entropy/pool_size)) - * - * For add_entropy <= pool_size/2 then - * (1 - exp(-add_entropy/pool_size)) >= - * (add_entropy/pool_size)*0.7869... - * so we can approximate the exponential with - * 3/4*add_entropy/pool_size and still be on the - * safe side by adding at most pool_size/2 at a time. - * - * The use of pool_size-2 in the while statement is to - * prevent rounding artifacts from making the loop - * arbitrarily long; this limits the loop to log2(pool_size)*2 - * turns no matter how large nbits is. - */ - int pnfrac = nfrac; - const int s = r->poolinfo->poolbitshift + ENTROPY_SHIFT + 2; - /* The +2 corresponds to the /4 in the denominator */ - - do { - unsigned int anfrac = min(pnfrac, pool_size/2); - unsigned int add = - ((pool_size - entropy_count)*anfrac*3) >> s; - - entropy_count += add; - pnfrac -= anfrac; - } while (unlikely(entropy_count < pool_size-2 && pnfrac)); - } + entropy_count += nbits; if (entropy_count < 0) { - pr_warn("random: negative entropy/overflow: pool %s count %d\n", - r->name, entropy_count); - WARN_ON(1); + DEBUG_ENT("negative entropy/overflow\n"); entropy_count = 0; - } else if (entropy_count > pool_size) - entropy_count = pool_size; + } else if (entropy_count > r->poolinfo->POOLBITS) + entropy_count = r->poolinfo->POOLBITS; if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig) goto retry; - r->entropy_total += nbits; - if (!r->initialized && r->entropy_total > 128) { - r->initialized = 1; - r->entropy_total = 0; - if (r == &nonblocking_pool) { - prandom_reseed_late(); - pr_notice("random: %s pool is initialized\n", r->name); - } + if (!r->initialized && nbits > 0) { + r->entropy_total += nbits; + if (r->entropy_total > 128) + r->initialized = 1; } - trace_credit_entropy_bits(r->name, nbits, - entropy_count >> ENTROPY_SHIFT, + trace_credit_entropy_bits(r->name, nbits, entropy_count, r->entropy_total, _RET_IP_); - if (r == &input_pool) { - int entropy_bytes = entropy_count >> ENTROPY_SHIFT; - - /* should we wake readers? */ - if (entropy_bytes >= random_read_wakeup_thresh) { - wake_up_interruptible(&random_read_wait); - kill_fasync(&fasync, SIGIO, POLL_IN); - } - /* If the input pool is getting full, send some - * entropy to the two output pools, flipping back and - * forth between them, until the output pools are 75% - * full. - */ - if (entropy_bytes > random_write_wakeup_thresh && - r->initialized && - r->entropy_total >= 2*random_read_wakeup_thresh) { - static struct entropy_store *last = &blocking_pool; - struct entropy_store *other = &blocking_pool; - - if (last == &blocking_pool) - other = &nonblocking_pool; - if (other->entropy_count <= - 3 * other->poolinfo->poolfracbits / 4) - last = other; - if (last->entropy_count <= - 3 * last->poolinfo->poolfracbits / 4) { - schedule_work(&last->push_work); - r->entropy_total = 0; - } - } + /* should we wake readers? */ + if (r == &input_pool && entropy_count >= random_read_wakeup_thresh) { + wake_up_interruptible(&random_read_wait); + kill_fasync(&fasync, SIGIO, POLL_IN); } } -static void credit_entropy_bits_safe(struct entropy_store *r, int nbits) -{ - const int nbits_max = (int)(~0U >> (ENTROPY_SHIFT + 1)); - - /* Cap the value to avoid overflows */ - nbits = min(nbits, nbits_max); - nbits = max(nbits, -nbits_max); - - credit_entropy_bits(r, nbits); -} - /********************************************************************* * * Entropy input management @@ -722,8 +630,6 @@ struct timer_rand_state { unsigned dont_count_entropy:1; }; -#define INIT_TIMER_RAND_STATE { INITIAL_JIFFIES, }; - /* * Add device- or boot-specific data to the input and nonblocking * pools to help initialize them to unique values. @@ -735,22 +641,15 @@ struct timer_rand_state { void add_device_randomness(const void *buf, unsigned int size) { unsigned long time = random_get_entropy() ^ jiffies; - unsigned long flags; - trace_add_device_randomness(size, _RET_IP_); - spin_lock_irqsave(&input_pool.lock, flags); - _mix_pool_bytes(&input_pool, buf, size, NULL); - _mix_pool_bytes(&input_pool, &time, sizeof(time), NULL); - spin_unlock_irqrestore(&input_pool.lock, flags); - - spin_lock_irqsave(&nonblocking_pool.lock, flags); - _mix_pool_bytes(&nonblocking_pool, buf, size, NULL); - _mix_pool_bytes(&nonblocking_pool, &time, sizeof(time), NULL); - spin_unlock_irqrestore(&nonblocking_pool.lock, flags); + mix_pool_bytes(&input_pool, buf, size, NULL); + mix_pool_bytes(&input_pool, &time, sizeof(time), NULL); + mix_pool_bytes(&nonblocking_pool, buf, size, NULL); + mix_pool_bytes(&nonblocking_pool, &time, sizeof(time), NULL); } EXPORT_SYMBOL(add_device_randomness); -static struct timer_rand_state input_timer_state = INIT_TIMER_RAND_STATE; +static struct timer_rand_state input_timer_state; /* * This function adds entropy to the entropy "pool" by using timing @@ -764,7 +663,6 @@ static struct timer_rand_state input_timer_state = INIT_TIMER_RAND_STATE; */ static void add_timer_randomness(struct timer_rand_state *state, unsigned num) { - struct entropy_store *r; struct { long jiffies; unsigned cycles; @@ -773,12 +671,15 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num) long delta, delta2, delta3; preempt_disable(); + /* if over the trickle threshold, use only 1 in 4096 samples */ + if (input_pool.entropy_count > trickle_thresh && + ((__this_cpu_inc_return(trickle_count) - 1) & 0xfff)) + goto out; sample.jiffies = jiffies; sample.cycles = random_get_entropy(); sample.num = num; - r = nonblocking_pool.initialized ? &input_pool : &nonblocking_pool; - mix_pool_bytes(r, &sample, sizeof(sample), NULL); + mix_pool_bytes(&input_pool, &sample, sizeof(sample), NULL); /* * Calculate number of bits of randomness we probably added. @@ -812,8 +713,10 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num) * Round down by 1 bit on general principles, * and limit entropy entimate to 12 bits. */ - credit_entropy_bits(r, min_t(int, fls(delta>>1), 11)); + credit_entropy_bits(&input_pool, + min_t(int, fls(delta>>1), 11)); } +out: preempt_enable(); } @@ -826,10 +729,10 @@ void add_input_randomness(unsigned int type, unsigned int code, if (value == last_value) return; + DEBUG_ENT("input event\n"); last_value = value; add_timer_randomness(&input_timer_state, (type << 4) ^ code ^ (code >> 4) ^ value); - trace_add_input_randomness(ENTROPY_BITS(&input_pool)); } EXPORT_SYMBOL_GPL(add_input_randomness); @@ -841,21 +744,20 @@ void add_interrupt_randomness(int irq, int irq_flags) struct fast_pool *fast_pool = &__get_cpu_var(irq_randomness); struct pt_regs *regs = get_irq_regs(); unsigned long now = jiffies; - cycles_t cycles = random_get_entropy(); - __u32 input[4], c_high, j_high; - __u64 ip; - - c_high = (sizeof(cycles) > 4) ? cycles >> 32 : 0; - j_high = (sizeof(now) > 4) ? now >> 32 : 0; - input[0] = cycles ^ j_high ^ irq; - input[1] = now ^ c_high; - ip = regs ? instruction_pointer(regs) : _RET_IP_; - input[2] = ip; - input[3] = ip >> 32; + __u32 input[4], cycles = random_get_entropy(); + + input[0] = cycles ^ jiffies; + input[1] = irq; + if (regs) { + __u64 ip = instruction_pointer(regs); + input[2] = ip; + input[3] = ip >> 32; + } - fast_mix(fast_pool, input); + fast_mix(fast_pool, input, sizeof(input)); - if ((fast_pool->count & 63) && !time_after(now, fast_pool->last + HZ)) + if ((fast_pool->count & 1023) && + !time_after(now, fast_pool->last + HZ)) return; fast_pool->last = now; @@ -884,8 +786,10 @@ void add_disk_randomness(struct gendisk *disk) if (!disk || !disk->random) return; /* first major is 1, so we get >= 0x200 here */ + DEBUG_ENT("disk event %d:%d\n", + MAJOR(disk_devt(disk)), MINOR(disk_devt(disk))); + add_timer_randomness(disk->random, 0x100 + disk_devt(disk)); - trace_add_disk_randomness(disk_devt(disk), ENTROPY_BITS(&input_pool)); } #endif @@ -903,58 +807,30 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf, * from the primary pool to the secondary extraction pool. We make * sure we pull enough for a 'catastrophic reseed'. */ -static void _xfer_secondary_pool(struct entropy_store *r, size_t nbytes); static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes) { - if (r->limit == 0 && random_min_urandom_seed) { - unsigned long now = jiffies; - - if (time_before(now, - r->last_pulled + random_min_urandom_seed * HZ)) - return; - r->last_pulled = now; - } - if (r->pull && - r->entropy_count < (nbytes << (ENTROPY_SHIFT + 3)) && - r->entropy_count < r->poolinfo->poolfracbits) - _xfer_secondary_pool(r, nbytes); -} - -static void _xfer_secondary_pool(struct entropy_store *r, size_t nbytes) -{ __u32 tmp[OUTPUT_POOL_WORDS]; - /* For /dev/random's pool, always leave two wakeup worth's BITS */ - int rsvd = r->limit ? 0 : random_read_wakeup_thresh/4; - int bytes = nbytes; - - /* pull at least as many as BYTES as wakeup BITS */ - bytes = max_t(int, bytes, random_read_wakeup_thresh / 8); - /* but never more than the buffer size */ - bytes = min_t(int, bytes, sizeof(tmp)); - - trace_xfer_secondary_pool(r->name, bytes * 8, nbytes * 8, - ENTROPY_BITS(r), ENTROPY_BITS(r->pull)); - bytes = extract_entropy(r->pull, tmp, bytes, - random_read_wakeup_thresh / 8, rsvd); - mix_pool_bytes(r, tmp, bytes, NULL); - credit_entropy_bits(r, bytes*8); -} - -/* - * Used as a workqueue function so that when the input pool is getting - * full, we can "spill over" some entropy to the output pools. That - * way the output pools can store some of the excess entropy instead - * of letting it go to waste. - */ -static void push_to_pool(struct work_struct *work) -{ - struct entropy_store *r = container_of(work, struct entropy_store, - push_work); - BUG_ON(!r); - _xfer_secondary_pool(r, random_read_wakeup_thresh/8); - trace_push_to_pool(r->name, r->entropy_count >> ENTROPY_SHIFT, - r->pull->entropy_count >> ENTROPY_SHIFT); + if (r->pull && r->entropy_count < nbytes * 8 && + r->entropy_count < r->poolinfo->POOLBITS) { + /* If we're limited, always leave two wakeup worth's BITS */ + int rsvd = r->limit ? 0 : random_read_wakeup_thresh/4; + int bytes = nbytes; + + /* pull at least as many as BYTES as wakeup BITS */ + bytes = max_t(int, bytes, random_read_wakeup_thresh / 8); + /* but never more than the buffer size */ + bytes = min_t(int, bytes, sizeof(tmp)); + + DEBUG_ENT("going to reseed %s with %d bits " + "(%zu of %d requested)\n", + r->name, bytes * 8, nbytes * 8, r->entropy_count); + + bytes = extract_entropy(r->pull, tmp, bytes, + random_read_wakeup_thresh / 8, rsvd); + mix_pool_bytes(r, tmp, bytes, NULL); + credit_entropy_bits(r, bytes*8); + } } /* @@ -974,48 +850,50 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min, { unsigned long flags; int wakeup_write = 0; - int have_bytes; - int entropy_count, orig; - size_t ibytes; /* Hold lock while accounting */ spin_lock_irqsave(&r->lock, flags); - BUG_ON(r->entropy_count > r->poolinfo->poolfracbits); + BUG_ON(r->entropy_count > r->poolinfo->POOLBITS); + DEBUG_ENT("trying to extract %zu bits from %s\n", + nbytes * 8, r->name); /* Can we pull enough? */ -retry: - entropy_count = orig = ACCESS_ONCE(r->entropy_count); - have_bytes = entropy_count >> (ENTROPY_SHIFT + 3); - ibytes = nbytes; - if (have_bytes < min + reserved) { - ibytes = 0; + if (r->entropy_count / 8 < min + reserved) { + nbytes = 0; } else { + int entropy_count, orig; +retry: + entropy_count = orig = ACCESS_ONCE(r->entropy_count); /* If limited, never pull more than available */ - if (r->limit && ibytes + reserved >= have_bytes) - ibytes = have_bytes - reserved; - - if (have_bytes >= ibytes + reserved) - entropy_count -= ibytes << (ENTROPY_SHIFT + 3); - else - entropy_count = reserved << (ENTROPY_SHIFT + 3); - - if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig) - goto retry; + if (r->limit && nbytes + reserved >= entropy_count / 8) + nbytes = entropy_count/8 - reserved; + + if (entropy_count / 8 >= nbytes + reserved) { + entropy_count -= nbytes*8; + if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig) + goto retry; + } else { + entropy_count = reserved; + if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig) + goto retry; + } - if ((r->entropy_count >> ENTROPY_SHIFT) - < random_write_wakeup_thresh) + if (entropy_count < random_write_wakeup_thresh) wakeup_write = 1; } + + DEBUG_ENT("debiting %zu entropy credits from %s%s\n", + nbytes * 8, r->name, r->limit ? "" : " (unlimited)"); + spin_unlock_irqrestore(&r->lock, flags); - trace_debit_entropy(r->name, 8 * ibytes); if (wakeup_write) { wake_up_interruptible(&random_write_wait); kill_fasync(&fasync, SIGIO, POLL_OUT); } - return ibytes; + return nbytes; } static void extract_buf(struct entropy_store *r, __u8 *out) @@ -1023,7 +901,7 @@ static void extract_buf(struct entropy_store *r, __u8 *out) int i; union { __u32 w[5]; - unsigned long l[LONGS(20)]; + unsigned long l[LONGS(EXTRACT_SIZE)]; } hash; __u32 workspace[SHA_WORKSPACE_WORDS]; __u8 extract[64]; @@ -1036,17 +914,6 @@ static void extract_buf(struct entropy_store *r, __u8 *out) sha_transform(hash.w, (__u8 *)(r->pool + i), workspace); /* - * If we have a architectural hardware random number - * generator, mix that in, too. - */ - for (i = 0; i < LONGS(20); i++) { - unsigned long v; - if (!arch_get_random_long(&v)) - break; - hash.l[i] ^= v; - } - - /* * We mix the hash back into the pool to prevent backtracking * attacks (where the attacker knows the state of the pool * plus the current outputs, and attempts to find previous @@ -1075,6 +942,17 @@ static void extract_buf(struct entropy_store *r, __u8 *out) hash.w[1] ^= hash.w[4]; hash.w[2] ^= rol32(hash.w[2], 16); + /* + * If we have a architectural hardware random number + * generator, mix that in, too. + */ + for (i = 0; i < LONGS(EXTRACT_SIZE); i++) { + unsigned long v; + if (!arch_get_random_long(&v)) + break; + hash.l[i] ^= v; + } + memcpy(out, &hash, EXTRACT_SIZE); memset(&hash, 0, sizeof(hash)); } @@ -1090,10 +968,10 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf, if (fips_enabled) { spin_lock_irqsave(&r->lock, flags); if (!r->last_data_init) { - r->last_data_init = 1; + r->last_data_init = true; spin_unlock_irqrestore(&r->lock, flags); trace_extract_entropy(r->name, EXTRACT_SIZE, - ENTROPY_BITS(r), _RET_IP_); + r->entropy_count, _RET_IP_); xfer_secondary_pool(r, EXTRACT_SIZE); extract_buf(r, tmp); spin_lock_irqsave(&r->lock, flags); @@ -1102,7 +980,7 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf, spin_unlock_irqrestore(&r->lock, flags); } - trace_extract_entropy(r->name, nbytes, ENTROPY_BITS(r), _RET_IP_); + trace_extract_entropy(r->name, nbytes, r->entropy_count, _RET_IP_); xfer_secondary_pool(r, nbytes); nbytes = account(r, nbytes, min, reserved); @@ -1135,7 +1013,7 @@ static ssize_t extract_entropy_user(struct entropy_store *r, void __user *buf, ssize_t ret = 0, i; __u8 tmp[EXTRACT_SIZE]; - trace_extract_entropy_user(r->name, nbytes, ENTROPY_BITS(r), _RET_IP_); + trace_extract_entropy_user(r->name, nbytes, r->entropy_count, _RET_IP_); xfer_secondary_pool(r, nbytes); nbytes = account(r, nbytes, 0, 0); @@ -1175,14 +1053,6 @@ static ssize_t extract_entropy_user(struct entropy_store *r, void __user *buf, */ void get_random_bytes(void *buf, int nbytes) { -#if DEBUG_RANDOM_BOOT > 0 - if (unlikely(nonblocking_pool.initialized == 0)) - printk(KERN_NOTICE "random: %pF get_random_bytes called " - "with %d bits of entropy available\n", - (void *) _RET_IP_, - nonblocking_pool.entropy_total); -#endif - trace_get_random_bytes(nbytes, _RET_IP_); extract_entropy(&nonblocking_pool, buf, nbytes, 0, 0); } EXPORT_SYMBOL(get_random_bytes); @@ -1201,7 +1071,7 @@ void get_random_bytes_arch(void *buf, int nbytes) { char *p = buf; - trace_get_random_bytes_arch(nbytes, _RET_IP_); + trace_get_random_bytes(nbytes, _RET_IP_); while (nbytes) { unsigned long v; int chunk = min(nbytes, (int)sizeof(unsigned long)); @@ -1235,11 +1105,13 @@ static void init_std_data(struct entropy_store *r) ktime_t now = ktime_get_real(); unsigned long rv; - r->last_pulled = jiffies; + r->entropy_count = 0; + r->entropy_total = 0; + r->last_data_init = false; mix_pool_bytes(r, &now, sizeof(now), NULL); - for (i = r->poolinfo->poolbytes; i > 0; i -= sizeof(rv)) { + for (i = r->poolinfo->POOLBYTES; i > 0; i -= sizeof(rv)) { if (!arch_get_random_long(&rv)) - rv = random_get_entropy(); + break; mix_pool_bytes(r, &rv, sizeof(rv), NULL); } mix_pool_bytes(r, utsname(), sizeof(*(utsname())), NULL); @@ -1262,7 +1134,7 @@ static int rand_initialize(void) init_std_data(&nonblocking_pool); return 0; } -early_initcall(rand_initialize); +module_init(rand_initialize); #ifdef CONFIG_BLOCK void rand_initialize_disk(struct gendisk *disk) @@ -1274,10 +1146,8 @@ void rand_initialize_disk(struct gendisk *disk) * source. */ state = kzalloc(sizeof(struct timer_rand_state), GFP_KERNEL); - if (state) { - state->last_time = INITIAL_JIFFIES; + if (state) disk->random = state; - } } #endif @@ -1294,6 +1164,8 @@ random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) if (n > SEC_XFER_SIZE) n = SEC_XFER_SIZE; + DEBUG_ENT("reading %zu bits\n", n*8); + n = extract_entropy_user(&blocking_pool, buf, n); if (n < 0) { @@ -1301,9 +1173,8 @@ random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) break; } - trace_random_read(n*8, (nbytes-n)*8, - ENTROPY_BITS(&blocking_pool), - ENTROPY_BITS(&input_pool)); + DEBUG_ENT("read got %zd bits (%zd still needed)\n", + n*8, (nbytes-n)*8); if (n == 0) { if (file->f_flags & O_NONBLOCK) { @@ -1311,9 +1182,13 @@ random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) break; } + DEBUG_ENT("sleeping?\n"); + wait_event_interruptible(random_read_wait, - ENTROPY_BITS(&input_pool) >= - random_read_wakeup_thresh); + input_pool.entropy_count >= + random_read_wakeup_thresh); + + DEBUG_ENT("awake\n"); if (signal_pending(current)) { retval = -ERESTARTSYS; @@ -1336,18 +1211,7 @@ random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) static ssize_t urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) { - int ret; - - if (unlikely(nonblocking_pool.initialized == 0)) - printk_once(KERN_NOTICE "random: %s urandom read " - "with %d bits of entropy available\n", - current->comm, nonblocking_pool.entropy_total); - - ret = extract_entropy_user(&nonblocking_pool, buf, nbytes); - - trace_urandom_read(8 * nbytes, ENTROPY_BITS(&nonblocking_pool), - ENTROPY_BITS(&input_pool)); - return ret; + return extract_entropy_user(&nonblocking_pool, buf, nbytes); } static unsigned int @@ -1358,9 +1222,9 @@ random_poll(struct file *file, poll_table * wait) poll_wait(file, &random_read_wait, wait); poll_wait(file, &random_write_wait, wait); mask = 0; - if (ENTROPY_BITS(&input_pool) >= random_read_wakeup_thresh) + if (input_pool.entropy_count >= random_read_wakeup_thresh) mask |= POLLIN | POLLRDNORM; - if (ENTROPY_BITS(&input_pool) < random_write_wakeup_thresh) + if (input_pool.entropy_count < random_write_wakeup_thresh) mask |= POLLOUT | POLLWRNORM; return mask; } @@ -1411,8 +1275,7 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg) switch (cmd) { case RNDGETENTCNT: /* inherently racy, no point locking */ - ent_count = ENTROPY_BITS(&input_pool); - if (put_user(ent_count, p)) + if (put_user(input_pool.entropy_count, p)) return -EFAULT; return 0; case RNDADDTOENTCNT: @@ -1420,7 +1283,7 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg) return -EPERM; if (get_user(ent_count, p)) return -EFAULT; - credit_entropy_bits_safe(&input_pool, ent_count); + credit_entropy_bits(&input_pool, ent_count); return 0; case RNDADDENTROPY: if (!capable(CAP_SYS_ADMIN)) @@ -1435,19 +1298,14 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg) size); if (retval < 0) return retval; - credit_entropy_bits_safe(&input_pool, ent_count); + credit_entropy_bits(&input_pool, ent_count); return 0; case RNDZAPENTCNT: case RNDCLEARPOOL: - /* - * Clear the entropy pool counters. We no longer clear - * the entropy pool, as that's silly. - */ + /* Clear the entropy pool counters. */ if (!capable(CAP_SYS_ADMIN)) return -EPERM; - input_pool.entropy_count = 0; - nonblocking_pool.entropy_count = 0; - blocking_pool.entropy_count = 0; + rand_initialize(); return 0; default: return -EINVAL; @@ -1547,23 +1405,6 @@ static int proc_do_uuid(struct ctl_table *table, int write, return proc_dostring(&fake_table, write, buffer, lenp, ppos); } -/* - * Return entropy available scaled to integral bits - */ -static int proc_do_entropy(ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - ctl_table fake_table; - int entropy_count; - - entropy_count = *(int *)table->data >> ENTROPY_SHIFT; - - fake_table.data = &entropy_count; - fake_table.maxlen = sizeof(entropy_count); - - return proc_dointvec(&fake_table, write, buffer, lenp, ppos); -} - static int sysctl_poolsize = INPUT_POOL_WORDS * 32; extern struct ctl_table random_table[]; struct ctl_table random_table[] = { @@ -1578,7 +1419,7 @@ struct ctl_table random_table[] = { .procname = "entropy_avail", .maxlen = sizeof(int), .mode = 0444, - .proc_handler = proc_do_entropy, + .proc_handler = proc_dointvec, .data = &input_pool.entropy_count, }, { @@ -1600,13 +1441,6 @@ struct ctl_table random_table[] = { .extra2 = &max_write_thresh, }, { - .procname = "urandom_min_reseed_secs", - .data = &random_min_urandom_seed, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { .procname = "boot_id", .data = &sysctl_bootid, .maxlen = 16, diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index 3525996..c0cbbd4 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -227,7 +227,7 @@ static inline unsigned char rtc_is_updating(void) #ifdef RTC_IRQ /* - * A very tiny interrupt handler. It runs with interrupts disabled, + * A very tiny interrupt handler. It runs with IRQF_DISABLED set, * but there is possibility of conflicting with the set_rtc_mmss() * call (the rtc irq and the timer irq can easily run at the same * time in two different CPUs). So we need to serialize @@ -1040,7 +1040,8 @@ no_irq: rtc_int_handler_ptr = rtc_interrupt; } - if (request_irq(RTC_IRQ, rtc_int_handler_ptr, 0, "rtc", NULL)) { + if (request_irq(RTC_IRQ, rtc_int_handler_ptr, IRQF_DISABLED, + "rtc", NULL)) { /* Yeah right, seeing as irq 8 doesn't even hit the bus. */ rtc_has_irq = 0; printk(KERN_ERR "rtc: IRQ %d is not free.\n", RTC_IRQ); diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c index 8bab592..5816b39 100644 --- a/drivers/char/snsc.c +++ b/drivers/char/snsc.c @@ -108,7 +108,8 @@ scdrv_open(struct inode *inode, struct file *file) /* hook this subchannel up to the system controller interrupt */ mutex_lock(&scdrv_mutex); rv = request_irq(SGI_UART_VECTOR, scdrv_interrupt, - IRQF_SHARED, SYSCTL_BASENAME, sd); + IRQF_SHARED | IRQF_DISABLED, + SYSCTL_BASENAME, sd); if (rv) { ia64_sn_irtr_close(sd->sd_nasid, sd->sd_subch); kfree(sd); diff --git a/drivers/char/snsc_event.c b/drivers/char/snsc_event.c index 59bcefd..ee15694 100644 --- a/drivers/char/snsc_event.c +++ b/drivers/char/snsc_event.c @@ -292,7 +292,8 @@ scdrv_event_init(struct sysctl_data_s *scd) /* hook event subchannel up to the system controller interrupt */ rv = request_irq(SGI_UART_VECTOR, scdrv_event_interrupt, - IRQF_SHARED, "system controller events", event_sd); + IRQF_SHARED | IRQF_DISABLED, + "system controller events", event_sd); if (rv) { printk(KERN_WARNING "%s: irq request failed (%d)\n", __func__, rv); diff --git a/drivers/char/tlclk.c b/drivers/char/tlclk.c index 100cd1d..e95e0ab 100644 --- a/drivers/char/tlclk.c +++ b/drivers/char/tlclk.c @@ -222,7 +222,7 @@ static int tlclk_open(struct inode *inode, struct file *filp) /* This device is wired through the FPGA IO space of the ATCA blade * we can't share this IRQ */ result = request_irq(telclk_interrupt, &tlclk_interrupt, - 0, "telco_clock", tlclk_interrupt); + IRQF_DISABLED, "telco_clock", tlclk_interrupt); if (result == -EBUSY) printk(KERN_ERR "tlclk: Interrupt can't be reserved.\n"); else diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index 1a65838..94c0c74 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -33,15 +33,6 @@ config TCG_TIS from within Linux. To compile this driver as a module, choose M here; the module will be called tpm_tis. -config TCG_TIS_I2C_ATMEL - tristate "TPM Interface Specification 1.2 Interface (I2C - Atmel)" - depends on I2C - ---help--- - If you have an Atmel I2C TPM security chip say Yes and it will be - accessible from within Linux. - To compile this driver as a module, choose M here; the module will - be called tpm_tis_i2c_atmel. - config TCG_TIS_I2C_INFINEON tristate "TPM Interface Specification 1.2 Interface (I2C - Infineon)" depends on I2C @@ -51,17 +42,7 @@ config TCG_TIS_I2C_INFINEON Specification 0.20 say Yes and it will be accessible from within Linux. To compile this driver as a module, choose M here; the module - will be called tpm_i2c_infineon. - -config TCG_TIS_I2C_NUVOTON - tristate "TPM Interface Specification 1.2 Interface (I2C - Nuvoton)" - depends on I2C - ---help--- - If you have a TPM security chip with an I2C interface from - Nuvoton Technology Corp. say Yes and it will be accessible - from within Linux. - To compile this driver as a module, choose M here; the module - will be called tpm_i2c_nuvoton. + will be called tpm_tis_i2c_infineon. config TCG_NSC tristate "National Semiconductor TPM Interface" @@ -101,14 +82,14 @@ config TCG_IBMVTPM as a module, choose M here; the module will be called tpm_ibmvtpm. config TCG_ST33_I2C - tristate "STMicroelectronics ST33 I2C TPM" - depends on I2C - depends on GPIOLIB - ---help--- - If you have a TPM security chip from STMicroelectronics working with - an I2C bus say Yes and it will be accessible from within Linux. - To compile this driver as a module, choose M here; the module will be - called tpm_stm_st33_i2c. + tristate "STMicroelectronics ST33 I2C TPM" + depends on I2C + depends on GPIOLIB + ---help--- + If you have a TPM security chip from STMicroelectronics working with + an I2C bus say Yes and it will be accessible from within Linux. + To compile this driver as a module, choose M here; the module will be + called tpm_stm_st33_i2c. config TCG_XEN tristate "XEN TPM Interface" diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile index b80a400..eb41ff9 100644 --- a/drivers/char/tpm/Makefile +++ b/drivers/char/tpm/Makefile @@ -2,20 +2,17 @@ # Makefile for the kernel tpm device drivers. # obj-$(CONFIG_TCG_TPM) += tpm.o -tpm-y := tpm-interface.o -tpm-$(CONFIG_ACPI) += tpm_ppi.o - ifdef CONFIG_ACPI - tpm-y += tpm_eventlog.o tpm_acpi.o + obj-$(CONFIG_TCG_TPM) += tpm_bios.o + tpm_bios-objs += tpm_eventlog.o tpm_acpi.o tpm_ppi.o else ifdef CONFIG_TCG_IBMVTPM - tpm-y += tpm_eventlog.o tpm_of.o + obj-$(CONFIG_TCG_TPM) += tpm_bios.o + tpm_bios-objs += tpm_eventlog.o tpm_of.o endif endif obj-$(CONFIG_TCG_TIS) += tpm_tis.o -obj-$(CONFIG_TCG_TIS_I2C_ATMEL) += tpm_i2c_atmel.o obj-$(CONFIG_TCG_TIS_I2C_INFINEON) += tpm_i2c_infineon.o -obj-$(CONFIG_TCG_TIS_I2C_NUVOTON) += tpm_i2c_nuvoton.o obj-$(CONFIG_TCG_NSC) += tpm_nsc.o obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm.c index 6ae41d3..e3c974a 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm.c @@ -10,13 +10,13 @@ * Maintained by: <tpmdd-devel@lists.sourceforge.net> * * Device driver for TCG/TCPA TPM (trusted platform module). - * Specifications at www.trustedcomputinggroup.org + * Specifications at www.trustedcomputinggroup.org * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, version 2 of the * License. - * + * * Note, the TPM chip is not interrupt driven (only polling) * and can have very long timeouts (minutes!). Hence the unusual * calls to msleep. @@ -371,14 +371,13 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, return -ENODATA; if (count > bufsiz) { dev_err(chip->dev, - "invalid count value %x %zx\n", count, bufsiz); + "invalid count value %x %zx \n", count, bufsiz); return -E2BIG; } mutex_lock(&chip->tpm_mutex); - rc = chip->vendor.send(chip, (u8 *) buf, count); - if (rc < 0) { + if ((rc = chip->vendor.send(chip, (u8 *) buf, count)) < 0) { dev_err(chip->dev, "tpm_transmit: tpm_send: error %zd\n", rc); goto out; @@ -445,7 +444,7 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd, { int err; - len = tpm_transmit(chip, (u8 *) cmd, len); + len = tpm_transmit(chip,(u8 *) cmd, len); if (len < 0) return len; else if (len < TPM_HEADER_SIZE) @@ -659,7 +658,7 @@ static int tpm_continue_selftest(struct tpm_chip *chip) return rc; } -ssize_t tpm_show_enabled(struct device *dev, struct device_attribute *attr, +ssize_t tpm_show_enabled(struct device * dev, struct device_attribute * attr, char *buf) { cap_t cap; @@ -675,7 +674,7 @@ ssize_t tpm_show_enabled(struct device *dev, struct device_attribute *attr, } EXPORT_SYMBOL_GPL(tpm_show_enabled); -ssize_t tpm_show_active(struct device *dev, struct device_attribute *attr, +ssize_t tpm_show_active(struct device * dev, struct device_attribute * attr, char *buf) { cap_t cap; @@ -691,7 +690,7 @@ ssize_t tpm_show_active(struct device *dev, struct device_attribute *attr, } EXPORT_SYMBOL_GPL(tpm_show_active); -ssize_t tpm_show_owned(struct device *dev, struct device_attribute *attr, +ssize_t tpm_show_owned(struct device * dev, struct device_attribute * attr, char *buf) { cap_t cap; @@ -707,8 +706,8 @@ ssize_t tpm_show_owned(struct device *dev, struct device_attribute *attr, } EXPORT_SYMBOL_GPL(tpm_show_owned); -ssize_t tpm_show_temp_deactivated(struct device *dev, - struct device_attribute *attr, char *buf) +ssize_t tpm_show_temp_deactivated(struct device * dev, + struct device_attribute * attr, char *buf) { cap_t cap; ssize_t rc; @@ -770,10 +769,10 @@ static int __tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) /** * tpm_pcr_read - read a pcr value - * @chip_num: tpm idx # or ANY + * @chip_num: tpm idx # or ANY * @pcr_idx: pcr idx to retrieve - * @res_buf: TPM_PCR value - * size of res_buf is 20 bytes (or NULL if you don't care) + * @res_buf: TPM_PCR value + * size of res_buf is 20 bytes (or NULL if you don't care) * * The TPM driver should be built-in, but for whatever reason it * isn't, protect against the chip disappearing, by incrementing @@ -795,9 +794,9 @@ EXPORT_SYMBOL_GPL(tpm_pcr_read); /** * tpm_pcr_extend - extend pcr value with hash - * @chip_num: tpm idx # or AN& + * @chip_num: tpm idx # or AN& * @pcr_idx: pcr idx to extend - * @hash: hash value used to extend pcr value + * @hash: hash value used to extend pcr value * * The TPM driver should be built-in, but for whatever reason it * isn't, protect against the chip disappearing, by incrementing @@ -848,7 +847,8 @@ int tpm_do_selftest(struct tpm_chip *chip) unsigned long duration; struct tpm_cmd_t cmd; - duration = tpm_calc_ordinal_duration(chip, TPM_ORD_CONTINUE_SELFTEST); + duration = tpm_calc_ordinal_duration(chip, + TPM_ORD_CONTINUE_SELFTEST); loops = jiffies_to_msecs(duration) / delay_msec; @@ -965,12 +965,12 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, if (err) goto out; - /* + /* ignore header 10 bytes algorithm 32 bits (1 == RSA ) encscheme 16 bits sigscheme 16 bits - parameters (RSA 12->bytes: keybit, #primes, expbit) + parameters (RSA 12->bytes: keybit, #primes, expbit) keylenbytes 32 bits 256 byte modulus ignore checksum 20 bytes @@ -1020,33 +1020,43 @@ ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr, str += sprintf(str, "Manufacturer: 0x%x\n", be32_to_cpu(cap.manufacturer_id)); - /* Try to get a TPM version 1.2 TPM_CAP_VERSION_INFO */ + rc = tpm_getcap(dev, CAP_VERSION_1_1, &cap, + "attempting to determine the 1.1 version"); + if (rc) + return 0; + str += sprintf(str, + "TCG version: %d.%d\nFirmware version: %d.%d\n", + cap.tpm_version.Major, cap.tpm_version.Minor, + cap.tpm_version.revMajor, cap.tpm_version.revMinor); + return str - buf; +} +EXPORT_SYMBOL_GPL(tpm_show_caps); + +ssize_t tpm_show_caps_1_2(struct device * dev, + struct device_attribute * attr, char *buf) +{ + cap_t cap; + ssize_t rc; + char *str = buf; + + rc = tpm_getcap(dev, TPM_CAP_PROP_MANUFACTURER, &cap, + "attempting to determine the manufacturer"); + if (rc) + return 0; + str += sprintf(str, "Manufacturer: 0x%x\n", + be32_to_cpu(cap.manufacturer_id)); rc = tpm_getcap(dev, CAP_VERSION_1_2, &cap, "attempting to determine the 1.2 version"); - if (!rc) { - str += sprintf(str, - "TCG version: %d.%d\nFirmware version: %d.%d\n", - cap.tpm_version_1_2.Major, - cap.tpm_version_1_2.Minor, - cap.tpm_version_1_2.revMajor, - cap.tpm_version_1_2.revMinor); - } else { - /* Otherwise just use TPM_STRUCT_VER */ - rc = tpm_getcap(dev, CAP_VERSION_1_1, &cap, - "attempting to determine the 1.1 version"); - if (rc) - return 0; - str += sprintf(str, - "TCG version: %d.%d\nFirmware version: %d.%d\n", - cap.tpm_version.Major, - cap.tpm_version.Minor, - cap.tpm_version.revMajor, - cap.tpm_version.revMinor); - } - + if (rc) + return 0; + str += sprintf(str, + "TCG version: %d.%d\nFirmware version: %d.%d\n", + cap.tpm_version_1_2.Major, cap.tpm_version_1_2.Minor, + cap.tpm_version_1_2.revMajor, + cap.tpm_version_1_2.revMinor); return str - buf; } -EXPORT_SYMBOL_GPL(tpm_show_caps); +EXPORT_SYMBOL_GPL(tpm_show_caps_1_2); ssize_t tpm_show_durations(struct device *dev, struct device_attribute *attr, char *buf) @@ -1092,8 +1102,8 @@ ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr, } EXPORT_SYMBOL_GPL(tpm_store_cancel); -static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask, - bool check_cancel, bool *canceled) +static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask, bool check_cancel, + bool *canceled) { u8 status = chip->vendor.status(chip); @@ -1160,25 +1170,38 @@ EXPORT_SYMBOL_GPL(wait_for_tpm_stat); */ int tpm_open(struct inode *inode, struct file *file) { - struct miscdevice *misc = file->private_data; - struct tpm_chip *chip = container_of(misc, struct tpm_chip, - vendor.miscdev); + int minor = iminor(inode); + struct tpm_chip *chip = NULL, *pos; + + rcu_read_lock(); + list_for_each_entry_rcu(pos, &tpm_chip_list, list) { + if (pos->vendor.miscdev.minor == minor) { + chip = pos; + get_device(chip->dev); + break; + } + } + rcu_read_unlock(); + + if (!chip) + return -ENODEV; if (test_and_set_bit(0, &chip->is_open)) { dev_dbg(chip->dev, "Another process owns this TPM\n"); + put_device(chip->dev); return -EBUSY; } chip->data_buffer = kzalloc(TPM_BUFSIZE, GFP_KERNEL); if (chip->data_buffer == NULL) { clear_bit(0, &chip->is_open); + put_device(chip->dev); return -ENOMEM; } atomic_set(&chip->data_pending, 0); file->private_data = chip; - get_device(chip->dev); return 0; } EXPORT_SYMBOL_GPL(tpm_open); @@ -1440,6 +1463,7 @@ void tpm_dev_vendor_release(struct tpm_chip *chip) chip->vendor.release(chip->dev); clear_bit(chip->dev_num, dev_mask); + kfree(chip->vendor.miscdev.name); } EXPORT_SYMBOL_GPL(tpm_dev_vendor_release); @@ -1463,7 +1487,7 @@ void tpm_dev_release(struct device *dev) EXPORT_SYMBOL_GPL(tpm_dev_release); /* - * Called from tpm_<specific>.c probe function only for devices + * Called from tpm_<specific>.c probe function only for devices * the driver has determined it should claim. Prior to calling * this function the specific probe function has called pci_enable_device * upon errant exit from this function specific probe function should call @@ -1472,13 +1496,17 @@ EXPORT_SYMBOL_GPL(tpm_dev_release); struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vendor_specific *entry) { +#define DEVNAME_SIZE 7 + + char *devname; struct tpm_chip *chip; /* Driver specific per-device data */ chip = kzalloc(sizeof(*chip), GFP_KERNEL); + devname = kmalloc(DEVNAME_SIZE, GFP_KERNEL); - if (chip == NULL) - return NULL; + if (chip == NULL || devname == NULL) + goto out_free; mutex_init(&chip->buffer_mutex); mutex_init(&chip->tpm_mutex); @@ -1503,9 +1531,8 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, set_bit(chip->dev_num, dev_mask); - scnprintf(chip->devname, sizeof(chip->devname), "%s%d", "tpm", - chip->dev_num); - chip->vendor.miscdev.name = chip->devname; + scnprintf(devname, DEVNAME_SIZE, "%s%d", "tpm", chip->dev_num); + chip->vendor.miscdev.name = devname; chip->vendor.miscdev.parent = dev; chip->dev = get_device(dev); @@ -1531,7 +1558,7 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, goto put_device; } - chip->bios_dir = tpm_bios_log_setup(chip->devname); + chip->bios_dir = tpm_bios_log_setup(devname); /* Make chip available */ spin_lock(&driver_lock); @@ -1544,6 +1571,7 @@ put_device: put_device(chip->dev); out_free: kfree(chip); + kfree(devname); return NULL; } EXPORT_SYMBOL_GPL(tpm_register_hardware); diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index f328478..a7bfc17 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -59,6 +59,8 @@ extern ssize_t tpm_show_pcrs(struct device *, struct device_attribute *attr, char *); extern ssize_t tpm_show_caps(struct device *, struct device_attribute *attr, char *); +extern ssize_t tpm_show_caps_1_2(struct device *, struct device_attribute *attr, + char *); extern ssize_t tpm_store_cancel(struct device *, struct device_attribute *attr, const char *, size_t); extern ssize_t tpm_show_enabled(struct device *, struct device_attribute *attr, @@ -120,7 +122,6 @@ struct tpm_chip { struct device *dev; /* Device stuff */ int dev_num; /* /dev/tpm# */ - char devname[7]; unsigned long is_open; /* only one allowed */ int time_expired; diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c index c9a528d..99d6820 100644 --- a/drivers/char/tpm/tpm_atmel.c +++ b/drivers/char/tpm/tpm_atmel.c @@ -202,7 +202,7 @@ static int __init init_atmel(void) have_region = (atmel_request_region - (base, region_size, "tpm_atmel0") == NULL) ? 0 : 1; + (tpm_atmel.base, region_size, "tpm_atmel0") == NULL) ? 0 : 1; pdev = platform_device_register_simple("tpm_atmel", -1, NULL, 0); if (IS_ERR(pdev)) { diff --git a/drivers/char/tpm/tpm_eventlog.c b/drivers/char/tpm/tpm_eventlog.c index 59f7cb2..84ddc55 100644 --- a/drivers/char/tpm/tpm_eventlog.c +++ b/drivers/char/tpm/tpm_eventlog.c @@ -406,6 +406,7 @@ out_tpm: out: return NULL; } +EXPORT_SYMBOL_GPL(tpm_bios_log_setup); void tpm_bios_log_teardown(struct dentry **lst) { @@ -414,3 +415,5 @@ void tpm_bios_log_teardown(struct dentry **lst) for (i = 0; i < 3; i++) securityfs_remove(lst[i]); } +EXPORT_SYMBOL_GPL(tpm_bios_log_teardown); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/tpm/tpm_i2c_atmel.c b/drivers/char/tpm/tpm_i2c_atmel.c deleted file mode 100644 index c3cd7fe..0000000 --- a/drivers/char/tpm/tpm_i2c_atmel.c +++ /dev/null @@ -1,284 +0,0 @@ -/* - * ATMEL I2C TPM AT97SC3204T - * - * Copyright (C) 2012 V Lab Technologies - * Teddy Reed <teddy@prosauce.org> - * Copyright (C) 2013, Obsidian Research Corp. - * Jason Gunthorpe <jgunthorpe@obsidianresearch.com> - * Device driver for ATMEL I2C TPMs. - * - * Teddy Reed determined the basic I2C command flow, unlike other I2C TPM - * devices the raw TCG formatted TPM command data is written via I2C and then - * raw TCG formatted TPM command data is returned via I2C. - * - * TGC status/locality/etc functions seen in the LPC implementation do not - * seem to be present. - * - * 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, see http://www.gnu.org/licenses/>. - */ -#include <linux/init.h> -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/slab.h> -#include <linux/i2c.h> -#include "tpm.h" - -#define I2C_DRIVER_NAME "tpm_i2c_atmel" - -#define TPM_I2C_SHORT_TIMEOUT 750 /* ms */ -#define TPM_I2C_LONG_TIMEOUT 2000 /* 2 sec */ - -#define ATMEL_STS_OK 1 - -struct priv_data { - size_t len; - /* This is the amount we read on the first try. 25 was chosen to fit a - * fair number of read responses in the buffer so a 2nd retry can be - * avoided in small message cases. */ - u8 buffer[sizeof(struct tpm_output_header) + 25]; -}; - -static int i2c_atmel_send(struct tpm_chip *chip, u8 *buf, size_t len) -{ - struct priv_data *priv = chip->vendor.priv; - struct i2c_client *client = to_i2c_client(chip->dev); - s32 status; - - priv->len = 0; - - if (len <= 2) - return -EIO; - - status = i2c_master_send(client, buf, len); - - dev_dbg(chip->dev, - "%s(buf=%*ph len=%0zx) -> sts=%d\n", __func__, - (int)min_t(size_t, 64, len), buf, len, status); - return status; -} - -static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count) -{ - struct priv_data *priv = chip->vendor.priv; - struct i2c_client *client = to_i2c_client(chip->dev); - struct tpm_output_header *hdr = - (struct tpm_output_header *)priv->buffer; - u32 expected_len; - int rc; - - if (priv->len == 0) - return -EIO; - - /* Get the message size from the message header, if we didn't get the - * whole message in read_status then we need to re-read the - * message. */ - expected_len = be32_to_cpu(hdr->length); - if (expected_len > count) - return -ENOMEM; - - if (priv->len >= expected_len) { - dev_dbg(chip->dev, - "%s early(buf=%*ph count=%0zx) -> ret=%d\n", __func__, - (int)min_t(size_t, 64, expected_len), buf, count, - expected_len); - memcpy(buf, priv->buffer, expected_len); - return expected_len; - } - - rc = i2c_master_recv(client, buf, expected_len); - dev_dbg(chip->dev, - "%s reread(buf=%*ph count=%0zx) -> ret=%d\n", __func__, - (int)min_t(size_t, 64, expected_len), buf, count, - expected_len); - return rc; -} - -static void i2c_atmel_cancel(struct tpm_chip *chip) -{ - dev_err(chip->dev, "TPM operation cancellation was requested, but is not supported"); -} - -static u8 i2c_atmel_read_status(struct tpm_chip *chip) -{ - struct priv_data *priv = chip->vendor.priv; - struct i2c_client *client = to_i2c_client(chip->dev); - int rc; - - /* The TPM fails the I2C read until it is ready, so we do the entire - * transfer here and buffer it locally. This way the common code can - * properly handle the timeouts. */ - priv->len = 0; - memset(priv->buffer, 0, sizeof(priv->buffer)); - - - /* Once the TPM has completed the command the command remains readable - * until another command is issued. */ - rc = i2c_master_recv(client, priv->buffer, sizeof(priv->buffer)); - dev_dbg(chip->dev, - "%s: sts=%d", __func__, rc); - if (rc <= 0) - return 0; - - priv->len = rc; - - return ATMEL_STS_OK; -} - -static const struct file_operations i2c_atmel_ops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .open = tpm_open, - .read = tpm_read, - .write = tpm_write, - .release = tpm_release, -}; - -static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); -static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); -static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL); -static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL); -static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL); -static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, NULL); -static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL); -static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); -static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL); -static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL); - -static struct attribute *i2c_atmel_attrs[] = { - &dev_attr_pubek.attr, - &dev_attr_pcrs.attr, - &dev_attr_enabled.attr, - &dev_attr_active.attr, - &dev_attr_owned.attr, - &dev_attr_temp_deactivated.attr, - &dev_attr_caps.attr, - &dev_attr_cancel.attr, - &dev_attr_durations.attr, - &dev_attr_timeouts.attr, - NULL, -}; - -static struct attribute_group i2c_atmel_attr_grp = { - .attrs = i2c_atmel_attrs -}; - -static bool i2c_atmel_req_canceled(struct tpm_chip *chip, u8 status) -{ - return 0; -} - -static const struct tpm_vendor_specific i2c_atmel = { - .status = i2c_atmel_read_status, - .recv = i2c_atmel_recv, - .send = i2c_atmel_send, - .cancel = i2c_atmel_cancel, - .req_complete_mask = ATMEL_STS_OK, - .req_complete_val = ATMEL_STS_OK, - .req_canceled = i2c_atmel_req_canceled, - .attr_group = &i2c_atmel_attr_grp, - .miscdev.fops = &i2c_atmel_ops, -}; - -static int i2c_atmel_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - int rc; - struct tpm_chip *chip; - struct device *dev = &client->dev; - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) - return -ENODEV; - - chip = tpm_register_hardware(dev, &i2c_atmel); - if (!chip) { - dev_err(dev, "%s() error in tpm_register_hardware\n", __func__); - return -ENODEV; - } - - chip->vendor.priv = devm_kzalloc(dev, sizeof(struct priv_data), - GFP_KERNEL); - - /* Default timeouts */ - chip->vendor.timeout_a = msecs_to_jiffies(TPM_I2C_SHORT_TIMEOUT); - chip->vendor.timeout_b = msecs_to_jiffies(TPM_I2C_LONG_TIMEOUT); - chip->vendor.timeout_c = msecs_to_jiffies(TPM_I2C_SHORT_TIMEOUT); - chip->vendor.timeout_d = msecs_to_jiffies(TPM_I2C_SHORT_TIMEOUT); - chip->vendor.irq = 0; - - /* There is no known way to probe for this device, and all version - * information seems to be read via TPM commands. Thus we rely on the - * TPM startup process in the common code to detect the device. */ - if (tpm_get_timeouts(chip)) { - rc = -ENODEV; - goto out_err; - } - - if (tpm_do_selftest(chip)) { - rc = -ENODEV; - goto out_err; - } - - return 0; - -out_err: - tpm_dev_vendor_release(chip); - tpm_remove_hardware(chip->dev); - return rc; -} - -static int i2c_atmel_remove(struct i2c_client *client) -{ - struct device *dev = &(client->dev); - struct tpm_chip *chip = dev_get_drvdata(dev); - - if (chip) - tpm_dev_vendor_release(chip); - tpm_remove_hardware(dev); - kfree(chip); - return 0; -} - -static const struct i2c_device_id i2c_atmel_id[] = { - {I2C_DRIVER_NAME, 0}, - {} -}; -MODULE_DEVICE_TABLE(i2c, i2c_atmel_id); - -#ifdef CONFIG_OF -static const struct of_device_id i2c_atmel_of_match[] = { - {.compatible = "atmel,at97sc3204t"}, - {}, -}; -MODULE_DEVICE_TABLE(of, i2c_atmel_of_match); -#endif - -static SIMPLE_DEV_PM_OPS(i2c_atmel_pm_ops, tpm_pm_suspend, tpm_pm_resume); - -static struct i2c_driver i2c_atmel_driver = { - .id_table = i2c_atmel_id, - .probe = i2c_atmel_probe, - .remove = i2c_atmel_remove, - .driver = { - .name = I2C_DRIVER_NAME, - .owner = THIS_MODULE, - .pm = &i2c_atmel_pm_ops, - .of_match_table = of_match_ptr(i2c_atmel_of_match), - }, -}; - -module_i2c_driver(i2c_atmel_driver); - -MODULE_AUTHOR("Jason Gunthorpe <jgunthorpe@obsidianresearch.com>"); -MODULE_DESCRIPTION("Atmel TPM I2C Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c index fefd2aa..b8735de 100644 --- a/drivers/char/tpm/tpm_i2c_infineon.c +++ b/drivers/char/tpm/tpm_i2c_infineon.c @@ -581,7 +581,7 @@ static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL); static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL); static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL); static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, NULL); -static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL); +static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps_1_2, NULL); static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL); static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL); @@ -685,6 +685,7 @@ out_vendor: chip->dev->release = NULL; chip->release = NULL; tpm_dev.client = NULL; + dev_set_drvdata(chip->dev, chip); out_err: return rc; } @@ -765,6 +766,7 @@ static int tpm_tis_i2c_remove(struct i2c_client *client) chip->dev->release = NULL; chip->release = NULL; tpm_dev.client = NULL; + dev_set_drvdata(chip->dev, chip); return 0; } diff --git a/drivers/char/tpm/tpm_i2c_nuvoton.c b/drivers/char/tpm/tpm_i2c_nuvoton.c deleted file mode 100644 index 6276fea..0000000 --- a/drivers/char/tpm/tpm_i2c_nuvoton.c +++ /dev/null @@ -1,710 +0,0 @@ -/****************************************************************************** - * Nuvoton TPM I2C Device Driver Interface for WPCT301/NPCT501, - * based on the TCG TPM Interface Spec version 1.2. - * Specifications at www.trustedcomputinggroup.org - * - * Copyright (C) 2011, Nuvoton Technology Corporation. - * Dan Morav <dan.morav@nuvoton.com> - * Copyright (C) 2013, Obsidian Research Corp. - * Jason Gunthorpe <jgunthorpe@obsidianresearch.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. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://www.gnu.org/licenses/>. - * - * Nuvoton contact information: APC.Support@nuvoton.com - *****************************************************************************/ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/wait.h> -#include <linux/i2c.h> -#include "tpm.h" - -/* I2C interface offsets */ -#define TPM_STS 0x00 -#define TPM_BURST_COUNT 0x01 -#define TPM_DATA_FIFO_W 0x20 -#define TPM_DATA_FIFO_R 0x40 -#define TPM_VID_DID_RID 0x60 -/* TPM command header size */ -#define TPM_HEADER_SIZE 10 -#define TPM_RETRY 5 -/* - * I2C bus device maximum buffer size w/o counting I2C address or command - * i.e. max size required for I2C write is 34 = addr, command, 32 bytes data - */ -#define TPM_I2C_MAX_BUF_SIZE 32 -#define TPM_I2C_RETRY_COUNT 32 -#define TPM_I2C_BUS_DELAY 1 /* msec */ -#define TPM_I2C_RETRY_DELAY_SHORT 2 /* msec */ -#define TPM_I2C_RETRY_DELAY_LONG 10 /* msec */ - -#define I2C_DRIVER_NAME "tpm_i2c_nuvoton" - -struct priv_data { - unsigned int intrs; -}; - -static s32 i2c_nuvoton_read_buf(struct i2c_client *client, u8 offset, u8 size, - u8 *data) -{ - s32 status; - - status = i2c_smbus_read_i2c_block_data(client, offset, size, data); - dev_dbg(&client->dev, - "%s(offset=%u size=%u data=%*ph) -> sts=%d\n", __func__, - offset, size, (int)size, data, status); - return status; -} - -static s32 i2c_nuvoton_write_buf(struct i2c_client *client, u8 offset, u8 size, - u8 *data) -{ - s32 status; - - status = i2c_smbus_write_i2c_block_data(client, offset, size, data); - dev_dbg(&client->dev, - "%s(offset=%u size=%u data=%*ph) -> sts=%d\n", __func__, - offset, size, (int)size, data, status); - return status; -} - -#define TPM_STS_VALID 0x80 -#define TPM_STS_COMMAND_READY 0x40 -#define TPM_STS_GO 0x20 -#define TPM_STS_DATA_AVAIL 0x10 -#define TPM_STS_EXPECT 0x08 -#define TPM_STS_RESPONSE_RETRY 0x02 -#define TPM_STS_ERR_VAL 0x07 /* bit2...bit0 reads always 0 */ - -#define TPM_I2C_SHORT_TIMEOUT 750 /* ms */ -#define TPM_I2C_LONG_TIMEOUT 2000 /* 2 sec */ - -/* read TPM_STS register */ -static u8 i2c_nuvoton_read_status(struct tpm_chip *chip) -{ - struct i2c_client *client = to_i2c_client(chip->dev); - s32 status; - u8 data; - - status = i2c_nuvoton_read_buf(client, TPM_STS, 1, &data); - if (status <= 0) { - dev_err(chip->dev, "%s() error return %d\n", __func__, - status); - data = TPM_STS_ERR_VAL; - } - - return data; -} - -/* write byte to TPM_STS register */ -static s32 i2c_nuvoton_write_status(struct i2c_client *client, u8 data) -{ - s32 status; - int i; - - /* this causes the current command to be aborted */ - for (i = 0, status = -1; i < TPM_I2C_RETRY_COUNT && status < 0; i++) { - status = i2c_nuvoton_write_buf(client, TPM_STS, 1, &data); - msleep(TPM_I2C_BUS_DELAY); - } - return status; -} - -/* write commandReady to TPM_STS register */ -static void i2c_nuvoton_ready(struct tpm_chip *chip) -{ - struct i2c_client *client = to_i2c_client(chip->dev); - s32 status; - - /* this causes the current command to be aborted */ - status = i2c_nuvoton_write_status(client, TPM_STS_COMMAND_READY); - if (status < 0) - dev_err(chip->dev, - "%s() fail to write TPM_STS.commandReady\n", __func__); -} - -/* read burstCount field from TPM_STS register - * return -1 on fail to read */ -static int i2c_nuvoton_get_burstcount(struct i2c_client *client, - struct tpm_chip *chip) -{ - unsigned long stop = jiffies + chip->vendor.timeout_d; - s32 status; - int burst_count = -1; - u8 data; - - /* wait for burstcount to be non-zero */ - do { - /* in I2C burstCount is 1 byte */ - status = i2c_nuvoton_read_buf(client, TPM_BURST_COUNT, 1, - &data); - if (status > 0 && data > 0) { - burst_count = min_t(u8, TPM_I2C_MAX_BUF_SIZE, data); - break; - } - msleep(TPM_I2C_BUS_DELAY); - } while (time_before(jiffies, stop)); - - return burst_count; -} - -/* - * WPCT301/NPCT501 SINT# supports only dataAvail - * any call to this function which is not waiting for dataAvail will - * set queue to NULL to avoid waiting for interrupt - */ -static bool i2c_nuvoton_check_status(struct tpm_chip *chip, u8 mask, u8 value) -{ - u8 status = i2c_nuvoton_read_status(chip); - return (status != TPM_STS_ERR_VAL) && ((status & mask) == value); -} - -static int i2c_nuvoton_wait_for_stat(struct tpm_chip *chip, u8 mask, u8 value, - u32 timeout, wait_queue_head_t *queue) -{ - if (chip->vendor.irq && queue) { - s32 rc; - DEFINE_WAIT(wait); - struct priv_data *priv = chip->vendor.priv; - unsigned int cur_intrs = priv->intrs; - - enable_irq(chip->vendor.irq); - rc = wait_event_interruptible_timeout(*queue, - cur_intrs != priv->intrs, - timeout); - if (rc > 0) - return 0; - /* At this point we know that the SINT pin is asserted, so we - * do not need to do i2c_nuvoton_check_status */ - } else { - unsigned long ten_msec, stop; - bool status_valid; - - /* check current status */ - status_valid = i2c_nuvoton_check_status(chip, mask, value); - if (status_valid) - return 0; - - /* use polling to wait for the event */ - ten_msec = jiffies + msecs_to_jiffies(TPM_I2C_RETRY_DELAY_LONG); - stop = jiffies + timeout; - do { - if (time_before(jiffies, ten_msec)) - msleep(TPM_I2C_RETRY_DELAY_SHORT); - else - msleep(TPM_I2C_RETRY_DELAY_LONG); - status_valid = i2c_nuvoton_check_status(chip, mask, - value); - if (status_valid) - return 0; - } while (time_before(jiffies, stop)); - } - dev_err(chip->dev, "%s(%02x, %02x) -> timeout\n", __func__, mask, - value); - return -ETIMEDOUT; -} - -/* wait for dataAvail field to be set in the TPM_STS register */ -static int i2c_nuvoton_wait_for_data_avail(struct tpm_chip *chip, u32 timeout, - wait_queue_head_t *queue) -{ - return i2c_nuvoton_wait_for_stat(chip, - TPM_STS_DATA_AVAIL | TPM_STS_VALID, - TPM_STS_DATA_AVAIL | TPM_STS_VALID, - timeout, queue); -} - -/* Read @count bytes into @buf from TPM_RD_FIFO register */ -static int i2c_nuvoton_recv_data(struct i2c_client *client, - struct tpm_chip *chip, u8 *buf, size_t count) -{ - s32 rc; - int burst_count, bytes2read, size = 0; - - while (size < count && - i2c_nuvoton_wait_for_data_avail(chip, - chip->vendor.timeout_c, - &chip->vendor.read_queue) == 0) { - burst_count = i2c_nuvoton_get_burstcount(client, chip); - if (burst_count < 0) { - dev_err(chip->dev, - "%s() fail to read burstCount=%d\n", __func__, - burst_count); - return -EIO; - } - bytes2read = min_t(size_t, burst_count, count - size); - rc = i2c_nuvoton_read_buf(client, TPM_DATA_FIFO_R, - bytes2read, &buf[size]); - if (rc < 0) { - dev_err(chip->dev, - "%s() fail on i2c_nuvoton_read_buf()=%d\n", - __func__, rc); - return -EIO; - } - dev_dbg(chip->dev, "%s(%d):", __func__, bytes2read); - size += bytes2read; - } - - return size; -} - -/* Read TPM command results */ -static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count) -{ - struct device *dev = chip->dev; - struct i2c_client *client = to_i2c_client(dev); - s32 rc; - int expected, status, burst_count, retries, size = 0; - - if (count < TPM_HEADER_SIZE) { - i2c_nuvoton_ready(chip); /* return to idle */ - dev_err(dev, "%s() count < header size\n", __func__); - return -EIO; - } - for (retries = 0; retries < TPM_RETRY; retries++) { - if (retries > 0) { - /* if this is not the first trial, set responseRetry */ - i2c_nuvoton_write_status(client, - TPM_STS_RESPONSE_RETRY); - } - /* - * read first available (> 10 bytes), including: - * tag, paramsize, and result - */ - status = i2c_nuvoton_wait_for_data_avail( - chip, chip->vendor.timeout_c, &chip->vendor.read_queue); - if (status != 0) { - dev_err(dev, "%s() timeout on dataAvail\n", __func__); - size = -ETIMEDOUT; - continue; - } - burst_count = i2c_nuvoton_get_burstcount(client, chip); - if (burst_count < 0) { - dev_err(dev, "%s() fail to get burstCount\n", __func__); - size = -EIO; - continue; - } - size = i2c_nuvoton_recv_data(client, chip, buf, - burst_count); - if (size < TPM_HEADER_SIZE) { - dev_err(dev, "%s() fail to read header\n", __func__); - size = -EIO; - continue; - } - /* - * convert number of expected bytes field from big endian 32 bit - * to machine native - */ - expected = be32_to_cpu(*(__be32 *) (buf + 2)); - if (expected > count) { - dev_err(dev, "%s() expected > count\n", __func__); - size = -EIO; - continue; - } - rc = i2c_nuvoton_recv_data(client, chip, &buf[size], - expected - size); - size += rc; - if (rc < 0 || size < expected) { - dev_err(dev, "%s() fail to read remainder of result\n", - __func__); - size = -EIO; - continue; - } - if (i2c_nuvoton_wait_for_stat( - chip, TPM_STS_VALID | TPM_STS_DATA_AVAIL, - TPM_STS_VALID, chip->vendor.timeout_c, - NULL)) { - dev_err(dev, "%s() error left over data\n", __func__); - size = -ETIMEDOUT; - continue; - } - break; - } - i2c_nuvoton_ready(chip); - dev_dbg(chip->dev, "%s() -> %d\n", __func__, size); - return size; -} - -/* - * Send TPM command. - * - * If interrupts are used (signaled by an irq set in the vendor structure) - * tpm.c can skip polling for the data to be available as the interrupt is - * waited for here - */ -static int i2c_nuvoton_send(struct tpm_chip *chip, u8 *buf, size_t len) -{ - struct device *dev = chip->dev; - struct i2c_client *client = to_i2c_client(dev); - u32 ordinal; - size_t count = 0; - int burst_count, bytes2write, retries, rc = -EIO; - - for (retries = 0; retries < TPM_RETRY; retries++) { - i2c_nuvoton_ready(chip); - if (i2c_nuvoton_wait_for_stat(chip, TPM_STS_COMMAND_READY, - TPM_STS_COMMAND_READY, - chip->vendor.timeout_b, NULL)) { - dev_err(dev, "%s() timeout on commandReady\n", - __func__); - rc = -EIO; - continue; - } - rc = 0; - while (count < len - 1) { - burst_count = i2c_nuvoton_get_burstcount(client, - chip); - if (burst_count < 0) { - dev_err(dev, "%s() fail get burstCount\n", - __func__); - rc = -EIO; - break; - } - bytes2write = min_t(size_t, burst_count, - len - 1 - count); - rc = i2c_nuvoton_write_buf(client, TPM_DATA_FIFO_W, - bytes2write, &buf[count]); - if (rc < 0) { - dev_err(dev, "%s() fail i2cWriteBuf\n", - __func__); - break; - } - dev_dbg(dev, "%s(%d):", __func__, bytes2write); - count += bytes2write; - rc = i2c_nuvoton_wait_for_stat(chip, - TPM_STS_VALID | - TPM_STS_EXPECT, - TPM_STS_VALID | - TPM_STS_EXPECT, - chip->vendor.timeout_c, - NULL); - if (rc < 0) { - dev_err(dev, "%s() timeout on Expect\n", - __func__); - rc = -ETIMEDOUT; - break; - } - } - if (rc < 0) - continue; - - /* write last byte */ - rc = i2c_nuvoton_write_buf(client, TPM_DATA_FIFO_W, 1, - &buf[count]); - if (rc < 0) { - dev_err(dev, "%s() fail to write last byte\n", - __func__); - rc = -EIO; - continue; - } - dev_dbg(dev, "%s(last): %02x", __func__, buf[count]); - rc = i2c_nuvoton_wait_for_stat(chip, - TPM_STS_VALID | TPM_STS_EXPECT, - TPM_STS_VALID, - chip->vendor.timeout_c, NULL); - if (rc) { - dev_err(dev, "%s() timeout on Expect to clear\n", - __func__); - rc = -ETIMEDOUT; - continue; - } - break; - } - if (rc < 0) { - /* retries == TPM_RETRY */ - i2c_nuvoton_ready(chip); - return rc; - } - /* execute the TPM command */ - rc = i2c_nuvoton_write_status(client, TPM_STS_GO); - if (rc < 0) { - dev_err(dev, "%s() fail to write Go\n", __func__); - i2c_nuvoton_ready(chip); - return rc; - } - ordinal = be32_to_cpu(*((__be32 *) (buf + 6))); - rc = i2c_nuvoton_wait_for_data_avail(chip, - tpm_calc_ordinal_duration(chip, - ordinal), - &chip->vendor.read_queue); - if (rc) { - dev_err(dev, "%s() timeout command duration\n", __func__); - i2c_nuvoton_ready(chip); - return rc; - } - - dev_dbg(dev, "%s() -> %zd\n", __func__, len); - return len; -} - -static bool i2c_nuvoton_req_canceled(struct tpm_chip *chip, u8 status) -{ - return (status == TPM_STS_COMMAND_READY); -} - -static const struct file_operations i2c_nuvoton_ops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .open = tpm_open, - .read = tpm_read, - .write = tpm_write, - .release = tpm_release, -}; - -static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); -static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); -static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL); -static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL); -static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL); -static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, NULL); -static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL); -static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); -static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL); -static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL); - -static struct attribute *i2c_nuvoton_attrs[] = { - &dev_attr_pubek.attr, - &dev_attr_pcrs.attr, - &dev_attr_enabled.attr, - &dev_attr_active.attr, - &dev_attr_owned.attr, - &dev_attr_temp_deactivated.attr, - &dev_attr_caps.attr, - &dev_attr_cancel.attr, - &dev_attr_durations.attr, - &dev_attr_timeouts.attr, - NULL, -}; - -static struct attribute_group i2c_nuvoton_attr_grp = { - .attrs = i2c_nuvoton_attrs -}; - -static const struct tpm_vendor_specific tpm_i2c = { - .status = i2c_nuvoton_read_status, - .recv = i2c_nuvoton_recv, - .send = i2c_nuvoton_send, - .cancel = i2c_nuvoton_ready, - .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, - .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, - .req_canceled = i2c_nuvoton_req_canceled, - .attr_group = &i2c_nuvoton_attr_grp, - .miscdev.fops = &i2c_nuvoton_ops, -}; - -/* The only purpose for the handler is to signal to any waiting threads that - * the interrupt is currently being asserted. The driver does not do any - * processing triggered by interrupts, and the chip provides no way to mask at - * the source (plus that would be slow over I2C). Run the IRQ as a one-shot, - * this means it cannot be shared. */ -static irqreturn_t i2c_nuvoton_int_handler(int dummy, void *dev_id) -{ - struct tpm_chip *chip = dev_id; - struct priv_data *priv = chip->vendor.priv; - - priv->intrs++; - wake_up(&chip->vendor.read_queue); - disable_irq_nosync(chip->vendor.irq); - return IRQ_HANDLED; -} - -static int get_vid(struct i2c_client *client, u32 *res) -{ - static const u8 vid_did_rid_value[] = { 0x50, 0x10, 0xfe }; - u32 temp; - s32 rc; - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -ENODEV; - rc = i2c_nuvoton_read_buf(client, TPM_VID_DID_RID, 4, (u8 *)&temp); - if (rc < 0) - return rc; - - /* check WPCT301 values - ignore RID */ - if (memcmp(&temp, vid_did_rid_value, sizeof(vid_did_rid_value))) { - /* - * f/w rev 2.81 has an issue where the VID_DID_RID is not - * reporting the right value. so give it another chance at - * offset 0x20 (FIFO_W). - */ - rc = i2c_nuvoton_read_buf(client, TPM_DATA_FIFO_W, 4, - (u8 *) (&temp)); - if (rc < 0) - return rc; - - /* check WPCT301 values - ignore RID */ - if (memcmp(&temp, vid_did_rid_value, - sizeof(vid_did_rid_value))) - return -ENODEV; - } - - *res = temp; - return 0; -} - -static int i2c_nuvoton_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - int rc; - struct tpm_chip *chip; - struct device *dev = &client->dev; - u32 vid = 0; - - rc = get_vid(client, &vid); - if (rc) - return rc; - - dev_info(dev, "VID: %04X DID: %02X RID: %02X\n", (u16) vid, - (u8) (vid >> 16), (u8) (vid >> 24)); - - chip = tpm_register_hardware(dev, &tpm_i2c); - if (!chip) { - dev_err(dev, "%s() error in tpm_register_hardware\n", __func__); - return -ENODEV; - } - - chip->vendor.priv = devm_kzalloc(dev, sizeof(struct priv_data), - GFP_KERNEL); - init_waitqueue_head(&chip->vendor.read_queue); - init_waitqueue_head(&chip->vendor.int_queue); - - /* Default timeouts */ - chip->vendor.timeout_a = msecs_to_jiffies(TPM_I2C_SHORT_TIMEOUT); - chip->vendor.timeout_b = msecs_to_jiffies(TPM_I2C_LONG_TIMEOUT); - chip->vendor.timeout_c = msecs_to_jiffies(TPM_I2C_SHORT_TIMEOUT); - chip->vendor.timeout_d = msecs_to_jiffies(TPM_I2C_SHORT_TIMEOUT); - - /* - * I2C intfcaps (interrupt capabilitieis) in the chip are hard coded to: - * TPM_INTF_INT_LEVEL_LOW | TPM_INTF_DATA_AVAIL_INT - * The IRQ should be set in the i2c_board_info (which is done - * automatically in of_i2c_register_devices, for device tree users */ - chip->vendor.irq = client->irq; - - if (chip->vendor.irq) { - dev_dbg(dev, "%s() chip-vendor.irq\n", __func__); - rc = devm_request_irq(dev, chip->vendor.irq, - i2c_nuvoton_int_handler, - IRQF_TRIGGER_LOW, - chip->vendor.miscdev.name, - chip); - if (rc) { - dev_err(dev, "%s() Unable to request irq: %d for use\n", - __func__, chip->vendor.irq); - chip->vendor.irq = 0; - } else { - /* Clear any pending interrupt */ - i2c_nuvoton_ready(chip); - /* - wait for TPM_STS==0xA0 (stsValid, commandReady) */ - rc = i2c_nuvoton_wait_for_stat(chip, - TPM_STS_COMMAND_READY, - TPM_STS_COMMAND_READY, - chip->vendor.timeout_b, - NULL); - if (rc == 0) { - /* - * TIS is in ready state - * write dummy byte to enter reception state - * TPM_DATA_FIFO_W <- rc (0) - */ - rc = i2c_nuvoton_write_buf(client, - TPM_DATA_FIFO_W, - 1, (u8 *) (&rc)); - if (rc < 0) - goto out_err; - /* TPM_STS <- 0x40 (commandReady) */ - i2c_nuvoton_ready(chip); - } else { - /* - * timeout_b reached - command was - * aborted. TIS should now be in idle state - - * only TPM_STS_VALID should be set - */ - if (i2c_nuvoton_read_status(chip) != - TPM_STS_VALID) { - rc = -EIO; - goto out_err; - } - } - } - } - - if (tpm_get_timeouts(chip)) { - rc = -ENODEV; - goto out_err; - } - - if (tpm_do_selftest(chip)) { - rc = -ENODEV; - goto out_err; - } - - return 0; - -out_err: - tpm_dev_vendor_release(chip); - tpm_remove_hardware(chip->dev); - return rc; -} - -static int i2c_nuvoton_remove(struct i2c_client *client) -{ - struct device *dev = &(client->dev); - struct tpm_chip *chip = dev_get_drvdata(dev); - - if (chip) - tpm_dev_vendor_release(chip); - tpm_remove_hardware(dev); - kfree(chip); - return 0; -} - - -static const struct i2c_device_id i2c_nuvoton_id[] = { - {I2C_DRIVER_NAME, 0}, - {} -}; -MODULE_DEVICE_TABLE(i2c, i2c_nuvoton_id); - -#ifdef CONFIG_OF -static const struct of_device_id i2c_nuvoton_of_match[] = { - {.compatible = "nuvoton,npct501"}, - {.compatible = "winbond,wpct301"}, - {}, -}; -MODULE_DEVICE_TABLE(of, i2c_nuvoton_of_match); -#endif - -static SIMPLE_DEV_PM_OPS(i2c_nuvoton_pm_ops, tpm_pm_suspend, tpm_pm_resume); - -static struct i2c_driver i2c_nuvoton_driver = { - .id_table = i2c_nuvoton_id, - .probe = i2c_nuvoton_probe, - .remove = i2c_nuvoton_remove, - .driver = { - .name = I2C_DRIVER_NAME, - .owner = THIS_MODULE, - .pm = &i2c_nuvoton_pm_ops, - .of_match_table = of_match_ptr(i2c_nuvoton_of_match), - }, -}; - -module_i2c_driver(i2c_nuvoton_driver); - -MODULE_AUTHOR("Dan Morav (dan.morav@nuvoton.com)"); -MODULE_DESCRIPTION("Nuvoton TPM I2C Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c index a0d6ceb5..5bb8e2d 100644 --- a/drivers/char/tpm/tpm_i2c_stm_st33.c +++ b/drivers/char/tpm/tpm_i2c_stm_st33.c @@ -584,7 +584,7 @@ static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL); static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL); static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL); static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, NULL); -static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL); +static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps_1_2, NULL); static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); static struct attribute *stm_tpm_attrs[] = { @@ -746,6 +746,8 @@ tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) tpm_get_timeouts(chip); + i2c_set_clientdata(client, chip); + dev_info(chip->dev, "TPM I2C Initialized\n"); return 0; _irq_set: @@ -805,18 +807,24 @@ static int tpm_st33_i2c_remove(struct i2c_client *client) #ifdef CONFIG_PM_SLEEP /* * tpm_st33_i2c_pm_suspend suspend the TPM device + * Added: Work around when suspend and no tpm application is running, suspend + * may fail because chip->data_buffer is not set (only set in tpm_open in Linux + * TPM core) * @param: client, the i2c_client drescription (TPM I2C description). * @param: mesg, the power management message. * @return: 0 in case of success. */ static int tpm_st33_i2c_pm_suspend(struct device *dev) { + struct tpm_chip *chip = dev_get_drvdata(dev); struct st33zp24_platform_data *pin_infos = dev->platform_data; int ret = 0; if (power_mgt) { gpio_set_value(pin_infos->io_lpcpd, 0); } else { + if (chip->data_buffer == NULL) + chip->data_buffer = pin_infos->tpm_i2c_buffer[0]; ret = tpm_pm_suspend(dev); } return ret; @@ -841,6 +849,8 @@ static int tpm_st33_i2c_pm_resume(struct device *dev) TPM_STS_VALID) == TPM_STS_VALID, chip->vendor.timeout_b); } else { + if (chip->data_buffer == NULL) + chip->data_buffer = pin_infos->tpm_i2c_buffer[0]; ret = tpm_pm_resume(dev); if (!ret) tpm_do_selftest(chip); diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c index 2783a42..56b07c3 100644 --- a/drivers/char/tpm/tpm_ibmvtpm.c +++ b/drivers/char/tpm/tpm_ibmvtpm.c @@ -98,7 +98,7 @@ static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count) if (count < len) { dev_err(ibmvtpm->dev, - "Invalid size in recv: count=%zd, crq_size=%d\n", + "Invalid size in recv: count=%ld, crq_size=%d\n", count, len); return -EIO; } @@ -136,7 +136,7 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count) if (count > ibmvtpm->rtce_size) { dev_err(ibmvtpm->dev, - "Invalid size in send: count=%zd, rtce_size=%d\n", + "Invalid size in send: count=%ld, rtce_size=%d\n", count, ibmvtpm->rtce_size); return -EIO; } @@ -419,7 +419,7 @@ static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL); static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL); static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, NULL); -static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL); +static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps_1_2, NULL); static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL); static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL); diff --git a/drivers/char/tpm/tpm_ppi.c b/drivers/char/tpm/tpm_ppi.c index 8e562dc..2168d15 100644 --- a/drivers/char/tpm/tpm_ppi.c +++ b/drivers/char/tpm/tpm_ppi.c @@ -452,8 +452,12 @@ int tpm_add_ppi(struct kobject *parent) { return sysfs_create_group(parent, &ppi_attr_grp); } +EXPORT_SYMBOL_GPL(tpm_add_ppi); void tpm_remove_ppi(struct kobject *parent) { sysfs_remove_group(parent, &ppi_attr_grp); } +EXPORT_SYMBOL_GPL(tpm_remove_ppi); + +MODULE_LICENSE("GPL"); diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 1b74459..5796d01 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -448,7 +448,7 @@ static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL); static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL); static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, NULL); -static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL); +static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps_1_2, NULL); static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL); static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL); diff --git a/drivers/char/tpm/xen-tpmfront.c b/drivers/char/tpm/xen-tpmfront.c index c8ff4df..94c280d 100644 --- a/drivers/char/tpm/xen-tpmfront.c +++ b/drivers/char/tpm/xen-tpmfront.c @@ -351,6 +351,8 @@ static int tpmfront_probe(struct xenbus_device *dev, tpm_get_timeouts(priv->chip); + dev_set_drvdata(&dev->dev, priv->chip); + return rv; } diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index feea87c..b79cf3e 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -577,8 +577,7 @@ static ssize_t __send_control_msg(struct ports_device *portdev, u32 port_id, spin_lock(&portdev->c_ovq_lock); if (virtqueue_add_outbuf(vq, sg, 1, &cpkt, GFP_ATOMIC) == 0) { virtqueue_kick(vq); - while (!virtqueue_get_buf(vq, &len) - && !virtqueue_is_broken(vq)) + while (!virtqueue_get_buf(vq, &len)) cpu_relax(); } spin_unlock(&portdev->c_ovq_lock); @@ -651,8 +650,7 @@ static ssize_t __send_to_port(struct port *port, struct scatterlist *sg, * we need to kmalloc a GFP_ATOMIC buffer each time the * console driver writes something out. */ - while (!virtqueue_get_buf(out_vq, &len) - && !virtqueue_is_broken(out_vq)) + while (!virtqueue_get_buf(out_vq, &len)) cpu_relax(); done: spin_unlock_irqrestore(&port->outvq_lock, flags); @@ -1839,8 +1837,12 @@ static void config_intr(struct virtio_device *vdev) struct port *port; u16 rows, cols; - virtio_cread(vdev, struct virtio_console_config, cols, &cols); - virtio_cread(vdev, struct virtio_console_config, rows, &rows); + vdev->config->get(vdev, + offsetof(struct virtio_console_config, cols), + &cols, sizeof(u16)); + vdev->config->get(vdev, + offsetof(struct virtio_console_config, rows), + &rows, sizeof(u16)); port = find_port_by_id(portdev, 0); set_console_size(port, rows, cols); @@ -2012,9 +2014,10 @@ static int virtcons_probe(struct virtio_device *vdev) /* Don't test MULTIPORT at all if we're rproc: not a valid feature! */ if (!is_rproc_serial(vdev) && - virtio_cread_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT, - struct virtio_console_config, max_nr_ports, - &portdev->config.max_nr_ports) == 0) { + virtio_config_val(vdev, VIRTIO_CONSOLE_F_MULTIPORT, + offsetof(struct virtio_console_config, + max_nr_ports), + &portdev->config.max_nr_ports) == 0) { multiport = true; } @@ -2139,7 +2142,7 @@ static struct virtio_device_id rproc_serial_id_table[] = { static unsigned int rproc_serial_features[] = { }; -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_PM static int virtcons_freeze(struct virtio_device *vdev) { struct ports_device *portdev; @@ -2217,7 +2220,7 @@ static struct virtio_driver virtio_console = { .probe = virtcons_probe, .remove = virtcons_remove, .config_changed = config_intr, -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_PM .freeze = virtcons_freeze, .restore = virtcons_restore, #endif diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c index f6345f9..5224da5 100644 --- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c +++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c @@ -721,7 +721,7 @@ static int hwicap_remove(struct device *dev) { struct hwicap_drvdata *drvdata; - drvdata = dev_get_drvdata(dev); + drvdata = (struct hwicap_drvdata *)dev_get_drvdata(dev); if (!drvdata) return 0; @@ -731,6 +731,7 @@ static int hwicap_remove(struct device *dev) iounmap(drvdata->base_address); release_mem_region(drvdata->mem_start, drvdata->mem_size); kfree(drvdata); + dev_set_drvdata(dev, NULL); mutex_lock(&icap_sem); probed_devices[MINOR(dev->devt)-XHWICAP_MINOR] = 0; |