diff options
Diffstat (limited to 'drivers/char')
35 files changed, 1520 insertions, 466 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 14219972c745..fa3243d71c76 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -522,10 +522,16 @@ 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. If this applies to your hardware, - say N here. + 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. config HANGCHECK_TIMER tristate "Hangcheck timer" diff --git a/drivers/char/bsr.c b/drivers/char/bsr.c index 97467053a01b..8fedbc250414 100644 --- a/drivers/char/bsr.c +++ b/drivers/char/bsr.c @@ -21,6 +21,7 @@ #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> @@ -95,6 +96,7 @@ bsr_size_show(struct device *dev, struct device_attribute *attr, char *buf) struct bsr_dev *bsr_dev = dev_get_drvdata(dev); return sprintf(buf, "%u\n", bsr_dev->bsr_bytes); } +static DEVICE_ATTR_RO(bsr_size); static ssize_t bsr_stride_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -102,20 +104,23 @@ bsr_stride_show(struct device *dev, struct device_attribute *attr, char *buf) struct bsr_dev *bsr_dev = dev_get_drvdata(dev); return sprintf(buf, "%u\n", bsr_dev->bsr_stride); } +static DEVICE_ATTR_RO(bsr_stride); static ssize_t -bsr_len_show(struct device *dev, struct device_attribute *attr, char *buf) +bsr_length_show(struct device *dev, struct device_attribute *attr, char *buf) { struct bsr_dev *bsr_dev = dev_get_drvdata(dev); return sprintf(buf, "%llu\n", bsr_dev->bsr_len); } +static DEVICE_ATTR_RO(bsr_length); -static struct device_attribute bsr_dev_attrs[] = { - __ATTR(bsr_size, S_IRUGO, bsr_size_show, NULL), - __ATTR(bsr_stride, S_IRUGO, bsr_stride_show, NULL), - __ATTR(bsr_length, S_IRUGO, bsr_len_show, NULL), - __ATTR_NULL +static struct attribute *bsr_dev_attrs[] = { + &dev_attr_bsr_size.attr, + &dev_attr_bsr_stride.attr, + &dev_attr_bsr_length.attr, + NULL, }; +ATTRIBUTE_GROUPS(bsr_dev); static int bsr_mmap(struct file *filp, struct vm_area_struct *vma) { @@ -308,7 +313,7 @@ static int __init bsr_init(void) ret = PTR_ERR(bsr_class); goto out_err_1; } - bsr_class->dev_attrs = bsr_dev_attrs; + bsr_class->dev_groups = bsr_dev_groups; ret = alloc_chrdev_region(&bsr_dev, 0, BSR_MAX_DEVS, "bsr"); bsr_major = MAJOR(bsr_dev); diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 448ce5e29c56..5d9c31dfc905 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -367,12 +367,29 @@ 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; @@ -381,10 +398,13 @@ 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 } +#endif static int hpet_fasync(int fd, struct file *file, int on) { @@ -486,8 +506,7 @@ 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 : IRQF_DISABLED; + irq_flags = devp->hd_flags & HPET_SHARED_IRQ ? IRQF_SHARED : 0; if (request_irq(irq, hpet_interrupt, irq_flags, devp->hd_name, (void *)devp)) { printk(KERN_ERR "hpet: IRQ %d is not free\n", irq); @@ -971,8 +990,6 @@ 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 40a865449f35..c206de2951f2 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -153,12 +153,12 @@ config HW_RANDOM_IXP4XX config HW_RANDOM_OMAP tristate "OMAP Random Number Generator support" - depends on HW_RANDOM && (ARCH_OMAP16XX || ARCH_OMAP2) + depends on HW_RANDOM && (ARCH_OMAP16XX || ARCH_OMAP2PLUS) default HW_RANDOM ---help--- This driver provides kernel-side support for the Random Number - Generator hardware found on OMAP16xx and OMAP24xx multimedia - processors. + Generator hardware found on OMAP16xx, OMAP2/3/4/5 and AM33xx/AM43xx + multimedia processors. To compile this driver as a module, choose M here: the module will be called omap-rng. @@ -290,6 +290,19 @@ 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 diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile index bed467c9300e..d7d2435ff7fa 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile @@ -24,6 +24,7 @@ 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 diff --git a/drivers/char/hw_random/mxc-rnga.c b/drivers/char/hw_random/mxc-rnga.c index 19a12ac64a9e..6a86b6f56af2 100644 --- a/drivers/char/hw_random/mxc-rnga.c +++ b/drivers/char/hw_random/mxc-rnga.c @@ -164,7 +164,9 @@ static int __init mxc_rnga_probe(struct platform_device *pdev) goto out; } - clk_prepare_enable(mxc_rng->clk); + err = clk_prepare_enable(mxc_rng->clk); + if (err) + goto out; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); mxc_rng->mem = devm_ioremap_resource(&pdev->dev, res); diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c index 6843ec87b98b..9b89ff4881de 100644 --- a/drivers/char/hw_random/omap-rng.c +++ b/drivers/char/hw_random/omap-rng.c @@ -24,57 +24,131 @@ #include <linux/delay.h> #include <linux/slab.h> #include <linux/pm_runtime.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_address.h> +#include <linux/interrupt.h> #include <asm/io.h> -#define RNG_OUT_REG 0x00 /* Output register */ -#define RNG_STAT_REG 0x04 /* Status register - [0] = STAT_BUSY */ -#define RNG_ALARM_REG 0x24 /* Alarm register - [7:0] = ALARM_COUNTER */ -#define RNG_CONFIG_REG 0x28 /* Configuration register - [11:6] = RESET_COUNT - [5:3] = RING2_DELAY - [2:0] = RING1_DELAY */ -#define RNG_REV_REG 0x3c /* Revision register - [7:0] = REV_NB */ -#define RNG_MASK_REG 0x40 /* Mask and reset register - [2] = IT_EN - [1] = SOFTRESET - [0] = AUTOIDLE */ -#define RNG_SYSSTATUS 0x44 /* System status - [0] = RESETDONE */ +#define RNG_REG_STATUS_RDY (1 << 0) + +#define RNG_REG_INTACK_RDY_MASK (1 << 0) +#define RNG_REG_INTACK_SHUTDOWN_OFLO_MASK (1 << 1) +#define RNG_SHUTDOWN_OFLO_MASK (1 << 1) + +#define RNG_CONTROL_STARTUP_CYCLES_SHIFT 16 +#define RNG_CONTROL_STARTUP_CYCLES_MASK (0xffff << 16) +#define RNG_CONTROL_ENABLE_TRNG_SHIFT 10 +#define RNG_CONTROL_ENABLE_TRNG_MASK (1 << 10) + +#define RNG_CONFIG_MAX_REFIL_CYCLES_SHIFT 16 +#define RNG_CONFIG_MAX_REFIL_CYCLES_MASK (0xffff << 16) +#define RNG_CONFIG_MIN_REFIL_CYCLES_SHIFT 0 +#define RNG_CONFIG_MIN_REFIL_CYCLES_MASK (0xff << 0) + +#define RNG_CONTROL_STARTUP_CYCLES 0xff +#define RNG_CONFIG_MIN_REFIL_CYCLES 0x21 +#define RNG_CONFIG_MAX_REFIL_CYCLES 0x22 + +#define RNG_ALARMCNT_ALARM_TH_SHIFT 0x0 +#define RNG_ALARMCNT_ALARM_TH_MASK (0xff << 0) +#define RNG_ALARMCNT_SHUTDOWN_TH_SHIFT 16 +#define RNG_ALARMCNT_SHUTDOWN_TH_MASK (0x1f << 16) +#define RNG_ALARM_THRESHOLD 0xff +#define RNG_SHUTDOWN_THRESHOLD 0x4 + +#define RNG_REG_FROENABLE_MASK 0xffffff +#define RNG_REG_FRODETUNE_MASK 0xffffff + +#define OMAP2_RNG_OUTPUT_SIZE 0x4 +#define OMAP4_RNG_OUTPUT_SIZE 0x8 + +enum { + RNG_OUTPUT_L_REG = 0, + RNG_OUTPUT_H_REG, + RNG_STATUS_REG, + RNG_INTMASK_REG, + RNG_INTACK_REG, + RNG_CONTROL_REG, + RNG_CONFIG_REG, + RNG_ALARMCNT_REG, + RNG_FROENABLE_REG, + RNG_FRODETUNE_REG, + RNG_ALARMMASK_REG, + RNG_ALARMSTOP_REG, + RNG_REV_REG, + RNG_SYSCONFIG_REG, +}; + +static const u16 reg_map_omap2[] = { + [RNG_OUTPUT_L_REG] = 0x0, + [RNG_STATUS_REG] = 0x4, + [RNG_CONFIG_REG] = 0x28, + [RNG_REV_REG] = 0x3c, + [RNG_SYSCONFIG_REG] = 0x40, +}; +static const u16 reg_map_omap4[] = { + [RNG_OUTPUT_L_REG] = 0x0, + [RNG_OUTPUT_H_REG] = 0x4, + [RNG_STATUS_REG] = 0x8, + [RNG_INTMASK_REG] = 0xc, + [RNG_INTACK_REG] = 0x10, + [RNG_CONTROL_REG] = 0x14, + [RNG_CONFIG_REG] = 0x18, + [RNG_ALARMCNT_REG] = 0x1c, + [RNG_FROENABLE_REG] = 0x20, + [RNG_FRODETUNE_REG] = 0x24, + [RNG_ALARMMASK_REG] = 0x28, + [RNG_ALARMSTOP_REG] = 0x2c, + [RNG_REV_REG] = 0x1FE0, + [RNG_SYSCONFIG_REG] = 0x1FE4, +}; + +struct omap_rng_dev; /** - * struct omap_rng_private_data - RNG IP block-specific data - * @base: virtual address of the beginning of the RNG IP block registers - * @mem_res: struct resource * for the IP block registers physical memory + * struct omap_rng_pdata - RNG IP block-specific data + * @regs: Pointer to the register offsets structure. + * @data_size: No. of bytes in RNG output. + * @data_present: Callback to determine if data is available. + * @init: Callback for IP specific initialization sequence. + * @cleanup: Callback for IP specific cleanup sequence. */ -struct omap_rng_private_data { - void __iomem *base; - struct resource *mem_res; +struct omap_rng_pdata { + u16 *regs; + u32 data_size; + u32 (*data_present)(struct omap_rng_dev *priv); + int (*init)(struct omap_rng_dev *priv); + void (*cleanup)(struct omap_rng_dev *priv); }; -static inline u32 omap_rng_read_reg(struct omap_rng_private_data *priv, int reg) +struct omap_rng_dev { + void __iomem *base; + struct device *dev; + const struct omap_rng_pdata *pdata; +}; + +static inline u32 omap_rng_read(struct omap_rng_dev *priv, u16 reg) { - return __raw_readl(priv->base + reg); + return __raw_readl(priv->base + priv->pdata->regs[reg]); } -static inline void omap_rng_write_reg(struct omap_rng_private_data *priv, - int reg, u32 val) +static inline void omap_rng_write(struct omap_rng_dev *priv, u16 reg, + u32 val) { - __raw_writel(val, priv->base + reg); + __raw_writel(val, priv->base + priv->pdata->regs[reg]); } static int omap_rng_data_present(struct hwrng *rng, int wait) { - struct omap_rng_private_data *priv; + struct omap_rng_dev *priv; int data, i; - priv = (struct omap_rng_private_data *)rng->priv; + priv = (struct omap_rng_dev *)rng->priv; for (i = 0; i < 20; i++) { - data = omap_rng_read_reg(priv, RNG_STAT_REG) ? 0 : 1; + data = priv->pdata->data_present(priv); if (data || !wait) break; /* RNG produces data fast enough (2+ MBit/sec, even @@ -89,27 +163,212 @@ static int omap_rng_data_present(struct hwrng *rng, int wait) static int omap_rng_data_read(struct hwrng *rng, u32 *data) { - struct omap_rng_private_data *priv; + struct omap_rng_dev *priv; + u32 data_size, i; + + priv = (struct omap_rng_dev *)rng->priv; + data_size = priv->pdata->data_size; + + for (i = 0; i < data_size / sizeof(u32); i++) + data[i] = omap_rng_read(priv, RNG_OUTPUT_L_REG + i); + + if (priv->pdata->regs[RNG_INTACK_REG]) + omap_rng_write(priv, RNG_INTACK_REG, RNG_REG_INTACK_RDY_MASK); + return data_size; +} + +static int omap_rng_init(struct hwrng *rng) +{ + struct omap_rng_dev *priv; - priv = (struct omap_rng_private_data *)rng->priv; + priv = (struct omap_rng_dev *)rng->priv; + return priv->pdata->init(priv); +} - *data = omap_rng_read_reg(priv, RNG_OUT_REG); +static void omap_rng_cleanup(struct hwrng *rng) +{ + struct omap_rng_dev *priv; - return sizeof(u32); + priv = (struct omap_rng_dev *)rng->priv; + priv->pdata->cleanup(priv); } static struct hwrng omap_rng_ops = { .name = "omap", .data_present = omap_rng_data_present, .data_read = omap_rng_data_read, + .init = omap_rng_init, + .cleanup = omap_rng_cleanup, +}; + +static inline u32 omap2_rng_data_present(struct omap_rng_dev *priv) +{ + return omap_rng_read(priv, RNG_STATUS_REG) ? 0 : 1; +} + +static int omap2_rng_init(struct omap_rng_dev *priv) +{ + omap_rng_write(priv, RNG_SYSCONFIG_REG, 0x1); + return 0; +} + +static void omap2_rng_cleanup(struct omap_rng_dev *priv) +{ + omap_rng_write(priv, RNG_SYSCONFIG_REG, 0x0); +} + +static struct omap_rng_pdata omap2_rng_pdata = { + .regs = (u16 *)reg_map_omap2, + .data_size = OMAP2_RNG_OUTPUT_SIZE, + .data_present = omap2_rng_data_present, + .init = omap2_rng_init, + .cleanup = omap2_rng_cleanup, }; +#if defined(CONFIG_OF) +static inline u32 omap4_rng_data_present(struct omap_rng_dev *priv) +{ + return omap_rng_read(priv, RNG_STATUS_REG) & RNG_REG_STATUS_RDY; +} + +static int omap4_rng_init(struct omap_rng_dev *priv) +{ + u32 val; + + /* Return if RNG is already running. */ + if (omap_rng_read(priv, RNG_CONFIG_REG) & RNG_CONTROL_ENABLE_TRNG_MASK) + return 0; + + val = RNG_CONFIG_MIN_REFIL_CYCLES << RNG_CONFIG_MIN_REFIL_CYCLES_SHIFT; + val |= RNG_CONFIG_MAX_REFIL_CYCLES << RNG_CONFIG_MAX_REFIL_CYCLES_SHIFT; + omap_rng_write(priv, RNG_CONFIG_REG, val); + + omap_rng_write(priv, RNG_FRODETUNE_REG, 0x0); + omap_rng_write(priv, RNG_FROENABLE_REG, RNG_REG_FROENABLE_MASK); + val = RNG_ALARM_THRESHOLD << RNG_ALARMCNT_ALARM_TH_SHIFT; + val |= RNG_SHUTDOWN_THRESHOLD << RNG_ALARMCNT_SHUTDOWN_TH_SHIFT; + omap_rng_write(priv, RNG_ALARMCNT_REG, val); + + val = RNG_CONTROL_STARTUP_CYCLES << RNG_CONTROL_STARTUP_CYCLES_SHIFT; + val |= RNG_CONTROL_ENABLE_TRNG_MASK; + omap_rng_write(priv, RNG_CONTROL_REG, val); + + return 0; +} + +static void omap4_rng_cleanup(struct omap_rng_dev *priv) +{ + int val; + + val = omap_rng_read(priv, RNG_CONTROL_REG); + val &= ~RNG_CONTROL_ENABLE_TRNG_MASK; + omap_rng_write(priv, RNG_CONFIG_REG, val); +} + +static irqreturn_t omap4_rng_irq(int irq, void *dev_id) +{ + struct omap_rng_dev *priv = dev_id; + u32 fro_detune, fro_enable; + + /* + * Interrupt raised by a fro shutdown threshold, do the following: + * 1. Clear the alarm events. + * 2. De tune the FROs which are shutdown. + * 3. Re enable the shutdown FROs. + */ + omap_rng_write(priv, RNG_ALARMMASK_REG, 0x0); + omap_rng_write(priv, RNG_ALARMSTOP_REG, 0x0); + + fro_enable = omap_rng_read(priv, RNG_FROENABLE_REG); + fro_detune = ~fro_enable & RNG_REG_FRODETUNE_MASK; + fro_detune = fro_detune | omap_rng_read(priv, RNG_FRODETUNE_REG); + fro_enable = RNG_REG_FROENABLE_MASK; + + omap_rng_write(priv, RNG_FRODETUNE_REG, fro_detune); + omap_rng_write(priv, RNG_FROENABLE_REG, fro_enable); + + omap_rng_write(priv, RNG_INTACK_REG, RNG_REG_INTACK_SHUTDOWN_OFLO_MASK); + + return IRQ_HANDLED; +} + +static struct omap_rng_pdata omap4_rng_pdata = { + .regs = (u16 *)reg_map_omap4, + .data_size = OMAP4_RNG_OUTPUT_SIZE, + .data_present = omap4_rng_data_present, + .init = omap4_rng_init, + .cleanup = omap4_rng_cleanup, +}; + +static const struct of_device_id omap_rng_of_match[] = { + { + .compatible = "ti,omap2-rng", + .data = &omap2_rng_pdata, + }, + { + .compatible = "ti,omap4-rng", + .data = &omap4_rng_pdata, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, omap_rng_of_match); + +static int of_get_omap_rng_device_details(struct omap_rng_dev *priv, + struct platform_device *pdev) +{ + const struct of_device_id *match; + struct device *dev = &pdev->dev; + int irq, err; + + match = of_match_device(of_match_ptr(omap_rng_of_match), dev); + if (!match) { + dev_err(dev, "no compatible OF match\n"); + return -EINVAL; + } + priv->pdata = match->data; + + if (of_device_is_compatible(dev->of_node, "ti,omap4-rng")) { + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "%s: error getting IRQ resource - %d\n", + __func__, irq); + return irq; + } + + err = devm_request_irq(dev, irq, omap4_rng_irq, + IRQF_TRIGGER_NONE, dev_name(dev), priv); + if (err) { + dev_err(dev, "unable to request irq %d, err = %d\n", + irq, err); + return err; + } + omap_rng_write(priv, RNG_INTMASK_REG, RNG_SHUTDOWN_OFLO_MASK); + } + return 0; +} +#else +static int of_get_omap_rng_device_details(struct omap_rng_dev *omap_rng, + struct platform_device *pdev) +{ + return -EINVAL; +} +#endif + +static int get_omap_rng_device_details(struct omap_rng_dev *omap_rng) +{ + /* Only OMAP2/3 can be non-DT */ + omap_rng->pdata = &omap2_rng_pdata; + return 0; +} + static int omap_rng_probe(struct platform_device *pdev) { - struct omap_rng_private_data *priv; + struct omap_rng_dev *priv; + struct resource *res; + struct device *dev = &pdev->dev; int ret; - priv = kzalloc(sizeof(struct omap_rng_private_data), GFP_KERNEL); + priv = devm_kzalloc(dev, sizeof(struct omap_rng_dev), GFP_KERNEL); if (!priv) { dev_err(&pdev->dev, "could not allocate memory\n"); return -ENOMEM; @@ -117,26 +376,29 @@ static int omap_rng_probe(struct platform_device *pdev) omap_rng_ops.priv = (unsigned long)priv; platform_set_drvdata(pdev, priv); + priv->dev = dev; - priv->mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->base = devm_ioremap_resource(&pdev->dev, priv->mem_res); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->base = devm_ioremap_resource(dev, res); if (IS_ERR(priv->base)) { ret = PTR_ERR(priv->base); goto err_ioremap; } - platform_set_drvdata(pdev, priv); pm_runtime_enable(&pdev->dev); pm_runtime_get_sync(&pdev->dev); + ret = (dev->of_node) ? of_get_omap_rng_device_details(priv, pdev) : + get_omap_rng_device_details(priv); + if (ret) + goto err_ioremap; + ret = hwrng_register(&omap_rng_ops); if (ret) goto err_register; dev_info(&pdev->dev, "OMAP Random Number Generator ver. %02x\n", - omap_rng_read_reg(priv, RNG_REV_REG)); - - omap_rng_write_reg(priv, RNG_MASK_REG, 0x1); + omap_rng_read(priv, RNG_REV_REG)); return 0; @@ -144,26 +406,21 @@ err_register: priv->base = NULL; pm_runtime_disable(&pdev->dev); err_ioremap: - kfree(priv); - + dev_err(dev, "initialization failed.\n"); return ret; } static int __exit omap_rng_remove(struct platform_device *pdev) { - struct omap_rng_private_data *priv = platform_get_drvdata(pdev); + struct omap_rng_dev *priv = platform_get_drvdata(pdev); hwrng_unregister(&omap_rng_ops); - omap_rng_write_reg(priv, RNG_MASK_REG, 0x0); + priv->pdata->cleanup(priv); pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); - release_mem_region(priv->mem_res->start, resource_size(priv->mem_res)); - - kfree(priv); - return 0; } @@ -171,9 +428,9 @@ static int __exit omap_rng_remove(struct platform_device *pdev) static int omap_rng_suspend(struct device *dev) { - struct omap_rng_private_data *priv = dev_get_drvdata(dev); + struct omap_rng_dev *priv = dev_get_drvdata(dev); - omap_rng_write_reg(priv, RNG_MASK_REG, 0x0); + priv->pdata->cleanup(priv); pm_runtime_put_sync(dev); return 0; @@ -181,10 +438,10 @@ static int omap_rng_suspend(struct device *dev) static int omap_rng_resume(struct device *dev) { - struct omap_rng_private_data *priv = dev_get_drvdata(dev); + struct omap_rng_dev *priv = dev_get_drvdata(dev); pm_runtime_get_sync(dev); - omap_rng_write_reg(priv, RNG_MASK_REG, 0x1); + priv->pdata->init(priv); return 0; } @@ -198,31 +455,18 @@ static SIMPLE_DEV_PM_OPS(omap_rng_pm, omap_rng_suspend, omap_rng_resume); #endif -/* work with hotplug and coldplug */ -MODULE_ALIAS("platform:omap_rng"); - static struct platform_driver omap_rng_driver = { .driver = { .name = "omap_rng", .owner = THIS_MODULE, .pm = OMAP_RNG_PM, + .of_match_table = of_match_ptr(omap_rng_of_match), }, .probe = omap_rng_probe, .remove = __exit_p(omap_rng_remove), }; -static int __init omap_rng_init(void) -{ - return platform_driver_register(&omap_rng_driver); -} - -static void __exit omap_rng_exit(void) -{ - platform_driver_unregister(&omap_rng_driver); -} - -module_init(omap_rng_init); -module_exit(omap_rng_exit); - +module_platform_driver(omap_rng_driver); +MODULE_ALIAS("platform:omap_rng"); MODULE_AUTHOR("Deepak Saxena (and others)"); MODULE_LICENSE("GPL"); diff --git a/drivers/char/hw_random/pasemi-rng.c b/drivers/char/hw_random/pasemi-rng.c index c6df5b29af08..c66279bb6ef3 100644 --- a/drivers/char/hw_random/pasemi-rng.c +++ b/drivers/char/hw_random/pasemi-rng.c @@ -24,6 +24,7 @@ #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/picoxcell-rng.c b/drivers/char/hw_random/picoxcell-rng.c index 973b95113edf..3d4c2293c6f5 100644 --- a/drivers/char/hw_random/picoxcell-rng.c +++ b/drivers/char/hw_random/picoxcell-rng.c @@ -33,7 +33,7 @@ static void __iomem *rng_base; static struct clk *rng_clk; -struct device *rng_dev; +static struct device *rng_dev; static inline u32 picoxcell_trng_read_csr(void) { diff --git a/drivers/char/hw_random/powernv-rng.c b/drivers/char/hw_random/powernv-rng.c new file mode 100644 index 000000000000..3f4f63204560 --- /dev/null +++ b/drivers/char/hw_random/powernv-rng.c @@ -0,0 +1,81 @@ +/* + * 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 732c330805fd..521f76b0934b 100644 --- a/drivers/char/hw_random/ppc4xx-rng.c +++ b/drivers/char/hw_random/ppc4xx-rng.c @@ -13,6 +13,7 @@ #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 5f1197929f0c..b761459a3436 100644 --- a/drivers/char/hw_random/pseries-rng.c +++ b/drivers/char/hw_random/pseries-rng.c @@ -17,6 +17,9 @@ * 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> @@ -25,10 +28,15 @@ static int pseries_rng_data_read(struct hwrng *rng, u32 *data) { - if (plpar_hcall(H_RANDOM, (unsigned long *)data) != H_SUCCESS) { - printk(KERN_ERR "pseries rng hcall error\n"); - return 0; + 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; } + + /* The hypervisor interface returns 64 bits */ return 8; } diff --git a/drivers/char/hw_random/timeriomem-rng.c b/drivers/char/hw_random/timeriomem-rng.c index d2120ba8f3f9..73ce739f8e19 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; - INIT_COMPLETION(priv->completion); + reinit_completion(&priv->completion); mod_timer(&priv->timer, priv->expires); return 4; diff --git a/drivers/char/hw_random/tx4939-rng.c b/drivers/char/hw_random/tx4939-rng.c index 00593c847cf0..09c5fbea2b93 100644 --- a/drivers/char/hw_random/tx4939-rng.c +++ b/drivers/char/hw_random/tx4939-rng.c @@ -110,12 +110,10 @@ static int __init tx4939_rng_probe(struct platform_device *dev) struct resource *r; int i; - r = platform_get_resource(dev, IORESOURCE_MEM, 0); - if (!r) - return -EBUSY; rngdev = devm_kzalloc(&dev->dev, sizeof(*rngdev), GFP_KERNEL); if (!rngdev) return -ENOMEM; + r = platform_get_resource(dev, IORESOURCE_MEM, 0); rngdev->base = devm_ioremap_resource(&dev->dev, r); if (IS_ERR(rngdev->base)) return PTR_ERR(rngdev->base); diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c index d0387a84eec1..e737772ad69a 100644 --- a/drivers/char/hw_random/via-rng.c +++ b/drivers/char/hw_random/via-rng.c @@ -29,6 +29,7 @@ #include <linux/kernel.h> #include <linux/hw_random.h> #include <linux/delay.h> +#include <asm/cpu_device_id.h> #include <asm/io.h> #include <asm/msr.h> #include <asm/cpufeature.h> @@ -220,5 +221,11 @@ static void __exit mod_exit(void) module_init(mod_init); module_exit(mod_exit); +static struct x86_cpu_id via_rng_cpu_id[] = { + X86_FEATURE_MATCH(X86_FEATURE_XSTORE), + {} +}; + MODULE_DESCRIPTION("H/W RNG driver for VIA CPU with PadLock"); MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(x86cpu, via_rng_cpu_id); diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c index ef46a9cfd832..c12398d1517c 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 +#ifdef CONFIG_PM_SLEEP 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 +#ifdef CONFIG_PM_SLEEP .freeze = virtrng_freeze, .restore = virtrng_restore, #endif diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c index d5a5f020810a..ec318bf434a6 100644 --- a/drivers/char/ipmi/ipmi_devintf.c +++ b/drivers/char/ipmi/ipmi_devintf.c @@ -810,6 +810,7 @@ static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd, struct ipmi_recv __user *precv64; struct ipmi_recv recv64; + memset(&recv64, 0, sizeof(recv64)); if (get_compat_ipmi_recv(&recv64, compat_ptr(arg))) return -EFAULT; diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 4445fa164a2d..ec4e10fcf1a5 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -1848,7 +1848,7 @@ int ipmi_request_settime(ipmi_user_t user, int retries, unsigned int retry_time_ms) { - unsigned char saddr, lun; + unsigned char saddr = 0, lun = 0; int rv; if (!user) diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index af4b23ffc5a6..15e4a6031934 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -71,6 +71,11 @@ #include <linux/of_address.h> #include <linux/of_irq.h> +#ifdef CONFIG_PARISC +#include <asm/hardware.h> /* for register_parisc_driver() stuff */ +#include <asm/parisc-device.h> +#endif + #define PFX "ipmi_si: " /* Measure times between events in the driver. */ @@ -298,6 +303,9 @@ static int pci_registered; #ifdef CONFIG_ACPI static int pnp_registered; #endif +#ifdef CONFIG_PARISC +static int parisc_registered; +#endif static unsigned int kipmid_max_busy_us[SI_MAX_PARMS]; static int num_max_busy_us; @@ -2279,6 +2287,8 @@ static struct pnp_driver ipmi_pnp_driver = { .remove = ipmi_pnp_remove, .id_table = pnp_dev_table, }; + +MODULE_DEVICE_TABLE(pnp, pnp_dev_table); #endif #ifdef CONFIG_DMI @@ -2697,6 +2707,62 @@ static struct platform_driver ipmi_driver = { .remove = ipmi_remove, }; +#ifdef CONFIG_PARISC +static int ipmi_parisc_probe(struct parisc_device *dev) +{ + struct smi_info *info; + + info = smi_info_alloc(); + + if (!info) { + dev_err(&dev->dev, + "could not allocate memory for PARISC probe\n"); + return -ENOMEM; + } + + info->si_type = SI_KCS; + info->addr_source = SI_DEVICETREE; + info->io_setup = mem_setup; + info->io.addr_type = IPMI_MEM_ADDR_SPACE; + info->io.addr_data = dev->hpa.start; + info->io.regsize = 1; + info->io.regspacing = 1; + info->io.regshift = 0; + info->irq = 0; /* no interrupt */ + info->irq_setup = NULL; + info->dev = &dev->dev; + + dev_dbg(&dev->dev, "addr 0x%lx\n", info->io.addr_data); + + dev_set_drvdata(&dev->dev, info); + + if (add_smi(info)) { + kfree(info); + return -EBUSY; + } + + return 0; +} + +static int ipmi_parisc_remove(struct parisc_device *dev) +{ + cleanup_one_si(dev_get_drvdata(&dev->dev)); + return 0; +} + +static struct parisc_device_id ipmi_parisc_tbl[] = { + { HPHW_MC, HVERSION_REV_ANY_ID, 0x004, 0xC0 }, + { 0, } +}; + +static struct parisc_driver ipmi_parisc_driver = { + .name = "ipmi", + .id_table = ipmi_parisc_tbl, + .probe = ipmi_parisc_probe, + .remove = ipmi_parisc_remove, +}; +#endif /* CONFIG_PARISC */ + static int wait_for_msg_done(struct smi_info *smi_info) { enum si_sm_result smi_result; @@ -3462,6 +3528,13 @@ static int init_ipmi_si(void) spmi_find_bmc(); #endif +#ifdef CONFIG_PARISC + register_parisc_driver(&ipmi_parisc_driver); + parisc_registered = 1; + /* poking PC IO addresses will crash machine, don't do it */ + si_trydefaults = 0; +#endif + /* We prefer devices with interrupts, but in the case of a machine with multiple BMCs we assume that there will be several instances of a given type so if we succeed in registering a type then also @@ -3608,6 +3681,10 @@ static void cleanup_ipmi_si(void) if (pnp_registered) pnp_unregister_driver(&ipmi_pnp_driver); #endif +#ifdef CONFIG_PARISC + if (parisc_registered) + unregister_parisc_driver(&ipmi_parisc_driver); +#endif platform_driver_unregister(&ipmi_driver); diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 190d4423653f..ffa97d261cf3 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 *old_fops, *new_fops = NULL; + const struct file_operations *new_fops = NULL; mutex_lock(&misc_mtx); @@ -141,17 +141,11 @@ static int misc_open(struct inode * inode, struct file * file) } err = 0; - old_fops = file->f_op; - file->f_op = new_fops; + replace_fops(file, new_fops); if (file->f_op->open) { file->private_data = c; - err=file->f_op->open(inode,file); - if (err) { - fops_put(file->f_op); - file->f_op = fops_get(old_fops); - } + err = file->f_op->open(inode,file); } - fops_put(old_fops); fail: mutex_unlock(&misc_mtx); return err; @@ -193,8 +187,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) { - mutex_unlock(&misc_mtx); - return -EBUSY; + err = -EBUSY; + goto out; } misc->minor = DYNAMIC_MINORS - i - 1; set_bit(i, misc_minors); @@ -203,8 +197,8 @@ int misc_register(struct miscdevice * misc) list_for_each_entry(c, &misc_list, list) { if (c->minor == misc->minor) { - mutex_unlock(&misc_mtx); - return -EBUSY; + err = -EBUSY; + goto out; } } } diff --git a/drivers/char/nwbutton.c b/drivers/char/nwbutton.c index cfdfe493c6af..1fd00dc06897 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, IRQF_DISABLED, + if (request_irq (IRQ_NETWINDER_BUTTON, button_handler, 0, "nwbutton", NULL)) { printk (KERN_WARNING "nwbutton: IRQ %d is not free.\n", IRQ_NETWINDER_BUTTON); diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 5c5cc00ebb07..d39cca659a3f 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -1182,14 +1182,14 @@ static irqreturn_t mgslpc_isr(int dummy, void *dev_id) } count++; - if (gis & (BIT1 + BIT0)) { + if (gis & (BIT1 | BIT0)) { isr = read_reg16(info, CHB + ISR); if (isr & IRQ_DCD) dcd_change(info, tty); if (isr & IRQ_CTS) cts_change(info, tty); } - if (gis & (BIT3 + BIT2)) + if (gis & (BIT3 | BIT2)) { isr = read_reg16(info, CHA + ISR); if (isr & IRQ_TIMER) { @@ -1210,7 +1210,7 @@ static irqreturn_t mgslpc_isr(int dummy, void *dev_id) if (isr & IRQ_RXTIME) { issue_command(info, CHA, CMD_RXFIFO_READ); } - if (isr & (IRQ_RXEOM + IRQ_RXFIFO)) { + if (isr & (IRQ_RXEOM | IRQ_RXFIFO)) { if (info->params.mode == MGSL_MODE_HDLC) rx_ready_hdlc(info, isr & IRQ_RXEOM); else @@ -3031,11 +3031,11 @@ static void loopback_enable(MGSLPC_INFO *info) unsigned char val; /* CCR1:02..00 CM[2..0] Clock Mode = 111 (clock mode 7) */ - val = read_reg(info, CHA + CCR1) | (BIT2 + BIT1 + BIT0); + val = read_reg(info, CHA + CCR1) | (BIT2 | BIT1 | BIT0); write_reg(info, CHA + CCR1, val); /* CCR2:04 SSEL Clock source select, 1=submode b */ - val = read_reg(info, CHA + CCR2) | (BIT4 + BIT5); + val = read_reg(info, CHA + CCR2) | (BIT4 | BIT5); write_reg(info, CHA + CCR2, val); /* set LinkSpeed if available, otherwise default to 2Mbps */ @@ -3125,10 +3125,10 @@ static void hdlc_mode(MGSLPC_INFO *info) val |= BIT4; break; // FM0 case HDLC_ENCODING_BIPHASE_MARK: - val |= BIT4 + BIT2; + val |= BIT4 | BIT2; break; // FM1 case HDLC_ENCODING_BIPHASE_LEVEL: - val |= BIT4 + BIT3; + val |= BIT4 | BIT3; break; // Manchester } write_reg(info, CHA + CCR0, val); @@ -3185,7 +3185,7 @@ static void hdlc_mode(MGSLPC_INFO *info) */ val = 0x00; if (info->params.crc_type == HDLC_CRC_NONE) - val |= BIT2 + BIT1; + val |= BIT2 | BIT1; if (info->params.preamble != HDLC_PREAMBLE_PATTERN_NONE) val |= BIT5; switch (info->params.preamble_length) @@ -3197,7 +3197,7 @@ static void hdlc_mode(MGSLPC_INFO *info) val |= BIT6; break; case HDLC_PREAMBLE_LENGTH_64BITS: - val |= BIT7 + BIT6; + val |= BIT7 | BIT6; break; } write_reg(info, CHA + CCR3, val); @@ -3264,8 +3264,8 @@ static void hdlc_mode(MGSLPC_INFO *info) clear_reg_bits(info, CHA + PVR, BIT3); irq_enable(info, CHA, - IRQ_RXEOM + IRQ_RXFIFO + IRQ_ALLSENT + - IRQ_UNDERRUN + IRQ_TXFIFO); + IRQ_RXEOM | IRQ_RXFIFO | IRQ_ALLSENT | + IRQ_UNDERRUN | IRQ_TXFIFO); issue_command(info, CHA, CMD_TXRESET + CMD_RXRESET); wait_command_complete(info, CHA); read_reg16(info, CHA + ISR); /* clear pending IRQs */ @@ -3582,8 +3582,8 @@ static void async_mode(MGSLPC_INFO *info) } else clear_reg_bits(info, CHA + PVR, BIT3); irq_enable(info, CHA, - IRQ_RXEOM + IRQ_RXFIFO + IRQ_BREAK_ON + IRQ_RXTIME + - IRQ_ALLSENT + IRQ_TXFIFO); + IRQ_RXEOM | IRQ_RXFIFO | IRQ_BREAK_ON | IRQ_RXTIME | + IRQ_ALLSENT | IRQ_TXFIFO); issue_command(info, CHA, CMD_TXRESET + CMD_RXRESET); wait_command_complete(info, CHA); read_reg16(info, CHA + ISR); /* clear pending IRQs */ diff --git a/drivers/char/random.c b/drivers/char/random.c index 0d91fe52f3f5..429b75bb60e8 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -255,10 +255,8 @@ #include <linux/fips.h> #include <linux/ptrace.h> #include <linux/kmemcheck.h> - -#ifdef CONFIG_GENERIC_HARDIRQS -# include <linux/irq.h> -#endif +#include <linux/workqueue.h> +#include <linux/irq.h> #include <asm/processor.h> #include <asm/uaccess.h> @@ -272,14 +270,28 @@ /* * Configuration information */ -#define INPUT_POOL_WORDS 128 -#define OUTPUT_POOL_WORDS 32 -#define SEC_XFER_SIZE 512 -#define EXTRACT_SIZE 10 +#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 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. */ @@ -290,108 +302,100 @@ 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 = 128; +static int random_write_wakeup_thresh = 28 * OUTPUT_POOL_WORDS; /* - * When the input pool goes over trickle_thresh, start dropping most - * samples to avoid wasting CPU time and reduce lock contention. + * 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. */ - -static int trickle_thresh __read_mostly = INPUT_POOL_WORDS * 28; - -static DEFINE_PER_CPU(int, trickle_count); +static int random_min_urandom_seed = 60; /* - * 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. + * 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. */ static struct poolinfo { - int poolwords; + int poolbitshift, poolwords, poolbytes, poolbits, poolfracbits; +#define S(x) ilog2(x)+5, (x), (x)*4, (x)*32, (x) << (ENTROPY_SHIFT+5) int tap1, tap2, tap3, tap4, tap5; } poolinfo_table[] = { - /* 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 }, + /* 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 }, #if 0 /* x^2048 + x^1638 + x^1231 + x^819 + x^411 + x + 1 -- 115 */ - { 2048, 1638, 1231, 819, 411, 1 }, + { S(2048), 1638, 1231, 819, 411, 1 }, /* x^1024 + x^817 + x^615 + x^412 + x^204 + x + 1 -- 290 */ - { 1024, 817, 615, 412, 204, 1 }, + { S(1024), 817, 615, 412, 204, 1 }, /* x^1024 + x^819 + x^616 + x^410 + x^207 + x^2 + 1 -- 115 */ - { 1024, 819, 616, 410, 207, 2 }, + { S(1024), 819, 616, 410, 207, 2 }, /* x^512 + x^411 + x^308 + x^208 + x^104 + x + 1 -- 225 */ - { 512, 411, 308, 208, 104, 1 }, + { S(512), 411, 308, 208, 104, 1 }, /* x^512 + x^409 + x^307 + x^206 + x^102 + x^2 + 1 -- 95 */ - { 512, 409, 307, 206, 102, 2 }, + { S(512), 409, 307, 206, 102, 2 }, /* x^512 + x^409 + x^309 + x^205 + x^103 + x^2 + 1 -- 95 */ - { 512, 409, 309, 205, 103, 2 }, + { S(512), 409, 309, 205, 103, 2 }, /* x^256 + x^205 + x^155 + x^101 + x^52 + x + 1 -- 125 */ - { 256, 205, 155, 101, 52, 1 }, + { S(256), 205, 155, 101, 52, 1 }, /* x^128 + x^103 + x^78 + x^51 + x^27 + x^2 + 1 -- 70 */ - { 128, 103, 78, 51, 27, 2 }, + { S(128), 103, 78, 51, 27, 2 }, /* x^64 + x^52 + x^39 + x^26 + x^14 + x + 1 -- 15 */ - { 64, 52, 39, 26, 14, 1 }, + { S(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 */ @@ -399,17 +403,6 @@ 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 @@ -420,23 +413,26 @@ module_param(debug, bool, 0644); struct entropy_store; struct entropy_store { /* read-only data: */ - struct poolinfo *poolinfo; + const struct poolinfo *poolinfo; __u32 *pool; const char *name; struct entropy_store *pull; - int limit; + struct work_struct push_work; /* read-write data: */ + unsigned long last_pulled; spinlock_t lock; - unsigned add_ptr; - unsigned input_rotate; + unsigned short add_ptr; + unsigned short input_rotate; int entropy_count; int entropy_total; unsigned int initialized:1; - bool last_data_init; + unsigned int limit:1; + unsigned int last_data_init:1; __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]; @@ -455,7 +451,9 @@ static struct entropy_store blocking_pool = { .limit = 1, .pull = &input_pool, .lock = __SPIN_LOCK_UNLOCKED(blocking_pool.lock), - .pool = blocking_pool_data + .pool = blocking_pool_data, + .push_work = __WORK_INITIALIZER(blocking_pool.push_work, + push_to_pool), }; static struct entropy_store nonblocking_pool = { @@ -463,7 +461,9 @@ static struct entropy_store nonblocking_pool = { .name = "nonblocking", .pull = &input_pool, .lock = __SPIN_LOCK_UNLOCKED(nonblocking_pool.lock), - .pool = nonblocking_pool_data + .pool = nonblocking_pool_data, + .push_work = __WORK_INITIALIZER(nonblocking_pool.push_work, + push_to_pool), }; static __u32 const twist_table[8] = { @@ -501,7 +501,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 & 31); + w = rol32(*bytes++, input_rotate); i = (i - 1) & wordmask; /* XOR in the various taps */ @@ -521,7 +521,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 += i ? 7 : 14; + input_rotate = (input_rotate + (i ? 7 : 14)) & 31; } ACCESS_ONCE(r->input_rotate) = input_rotate; @@ -564,62 +564,151 @@ 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, const void *in, int nbytes) +static void fast_mix(struct fast_pool *f, __u32 input[4]) { - const char *bytes = in; __u32 w; - unsigned i = f->count; unsigned input_rotate = f->rotate; - 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; + 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; + f->rotate = input_rotate; + f->count++; } /* - * Credit (or debit) the entropy store with n bits of entropy + * 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. */ 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); - entropy_count += nbits; + 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)); + } if (entropy_count < 0) { - DEBUG_ENT("negative entropy/overflow\n"); + pr_warn("random: negative entropy/overflow: pool %s count %d\n", + r->name, entropy_count); + WARN_ON(1); entropy_count = 0; - } else if (entropy_count > r->poolinfo->POOLBITS) - entropy_count = r->poolinfo->POOLBITS; + } else if (entropy_count > pool_size) + entropy_count = pool_size; if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig) goto retry; - if (!r->initialized && nbits > 0) { - r->entropy_total += nbits; - if (r->entropy_total > 128) - r->initialized = 1; + 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); + } } - trace_credit_entropy_bits(r->name, nbits, entropy_count, + trace_credit_entropy_bits(r->name, nbits, + entropy_count >> ENTROPY_SHIFT, r->entropy_total, _RET_IP_); - /* 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); + 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; + } + } } } +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 @@ -633,6 +722,8 @@ 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. @@ -643,16 +734,23 @@ struct timer_rand_state { */ void add_device_randomness(const void *buf, unsigned int size) { - unsigned long time = get_cycles() ^ jiffies; + 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); - 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); + 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); } EXPORT_SYMBOL(add_device_randomness); -static struct timer_rand_state input_timer_state; +static struct timer_rand_state input_timer_state = INIT_TIMER_RAND_STATE; /* * This function adds entropy to the entropy "pool" by using timing @@ -666,6 +764,7 @@ static struct timer_rand_state input_timer_state; */ static void add_timer_randomness(struct timer_rand_state *state, unsigned num) { + struct entropy_store *r; struct { long jiffies; unsigned cycles; @@ -674,15 +773,12 @@ 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 = get_cycles(); + sample.cycles = random_get_entropy(); sample.num = num; - mix_pool_bytes(&input_pool, &sample, sizeof(sample), NULL); + r = nonblocking_pool.initialized ? &input_pool : &nonblocking_pool; + mix_pool_bytes(r, &sample, sizeof(sample), NULL); /* * Calculate number of bits of randomness we probably added. @@ -716,10 +812,8 @@ 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(&input_pool, - min_t(int, fls(delta>>1), 11)); + credit_entropy_bits(r, min_t(int, fls(delta>>1), 11)); } -out: preempt_enable(); } @@ -732,10 +826,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); @@ -747,20 +841,21 @@ 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; - __u32 input[4], cycles = get_cycles(); - - input[0] = cycles ^ jiffies; - input[1] = irq; - if (regs) { - __u64 ip = instruction_pointer(regs); - input[2] = ip; - input[3] = ip >> 32; - } + 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; - fast_mix(fast_pool, input, sizeof(input)); + fast_mix(fast_pool, input); - if ((fast_pool->count & 1023) && - !time_after(now, fast_pool->last + HZ)) + if ((fast_pool->count & 63) && !time_after(now, fast_pool->last + HZ)) return; fast_pool->last = now; @@ -789,10 +884,8 @@ 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 @@ -810,30 +903,58 @@ 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) { - __u32 tmp[OUTPUT_POOL_WORDS]; + if (r->limit == 0 && random_min_urandom_seed) { + unsigned long now = jiffies; - 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); + 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); } /* @@ -853,50 +974,48 @@ 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->POOLBITS); - DEBUG_ENT("trying to extract %zu bits from %s\n", - nbytes * 8, r->name); + BUG_ON(r->entropy_count > r->poolinfo->poolfracbits); /* Can we pull enough? */ - if (r->entropy_count / 8 < min + reserved) { - nbytes = 0; - } else { - int entropy_count, orig; retry: - entropy_count = orig = ACCESS_ONCE(r->entropy_count); + entropy_count = orig = ACCESS_ONCE(r->entropy_count); + have_bytes = entropy_count >> (ENTROPY_SHIFT + 3); + ibytes = nbytes; + if (have_bytes < min + reserved) { + ibytes = 0; + } else { /* If limited, never pull more than available */ - 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->limit && ibytes + reserved >= have_bytes) + ibytes = have_bytes - reserved; - if (entropy_count < random_write_wakeup_thresh) - wakeup_write = 1; - } + if (have_bytes >= ibytes + reserved) + entropy_count -= ibytes << (ENTROPY_SHIFT + 3); + else + entropy_count = reserved << (ENTROPY_SHIFT + 3); - DEBUG_ENT("debiting %zu entropy credits from %s%s\n", - nbytes * 8, r->name, r->limit ? "" : " (unlimited)"); + if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig) + goto retry; + if ((r->entropy_count >> ENTROPY_SHIFT) + < random_write_wakeup_thresh) + wakeup_write = 1; + } 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 nbytes; + return ibytes; } static void extract_buf(struct entropy_store *r, __u8 *out) @@ -904,7 +1023,7 @@ static void extract_buf(struct entropy_store *r, __u8 *out) int i; union { __u32 w[5]; - unsigned long l[LONGS(EXTRACT_SIZE)]; + unsigned long l[LONGS(20)]; } hash; __u32 workspace[SHA_WORKSPACE_WORDS]; __u8 extract[64]; @@ -917,6 +1036,17 @@ 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 @@ -945,17 +1075,6 @@ 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)); } @@ -971,10 +1090,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 = true; + r->last_data_init = 1; spin_unlock_irqrestore(&r->lock, flags); trace_extract_entropy(r->name, EXTRACT_SIZE, - r->entropy_count, _RET_IP_); + ENTROPY_BITS(r), _RET_IP_); xfer_secondary_pool(r, EXTRACT_SIZE); extract_buf(r, tmp); spin_lock_irqsave(&r->lock, flags); @@ -983,7 +1102,7 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf, spin_unlock_irqrestore(&r->lock, flags); } - trace_extract_entropy(r->name, nbytes, r->entropy_count, _RET_IP_); + trace_extract_entropy(r->name, nbytes, ENTROPY_BITS(r), _RET_IP_); xfer_secondary_pool(r, nbytes); nbytes = account(r, nbytes, min, reserved); @@ -1016,7 +1135,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, r->entropy_count, _RET_IP_); + trace_extract_entropy_user(r->name, nbytes, ENTROPY_BITS(r), _RET_IP_); xfer_secondary_pool(r, nbytes); nbytes = account(r, nbytes, 0, 0); @@ -1056,6 +1175,14 @@ 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); @@ -1074,7 +1201,7 @@ void get_random_bytes_arch(void *buf, int nbytes) { char *p = buf; - trace_get_random_bytes(nbytes, _RET_IP_); + trace_get_random_bytes_arch(nbytes, _RET_IP_); while (nbytes) { unsigned long v; int chunk = min(nbytes, (int)sizeof(unsigned long)); @@ -1108,13 +1235,11 @@ static void init_std_data(struct entropy_store *r) ktime_t now = ktime_get_real(); unsigned long rv; - r->entropy_count = 0; - r->entropy_total = 0; - r->last_data_init = false; + r->last_pulled = jiffies; 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)) - break; + rv = random_get_entropy(); mix_pool_bytes(r, &rv, sizeof(rv), NULL); } mix_pool_bytes(r, utsname(), sizeof(*(utsname())), NULL); @@ -1137,7 +1262,7 @@ static int rand_initialize(void) init_std_data(&nonblocking_pool); return 0; } -module_init(rand_initialize); +early_initcall(rand_initialize); #ifdef CONFIG_BLOCK void rand_initialize_disk(struct gendisk *disk) @@ -1149,8 +1274,10 @@ void rand_initialize_disk(struct gendisk *disk) * source. */ state = kzalloc(sizeof(struct timer_rand_state), GFP_KERNEL); - if (state) + if (state) { + state->last_time = INITIAL_JIFFIES; disk->random = state; + } } #endif @@ -1167,8 +1294,6 @@ 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) { @@ -1176,8 +1301,9 @@ random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) break; } - DEBUG_ENT("read got %zd bits (%zd still needed)\n", - n*8, (nbytes-n)*8); + trace_random_read(n*8, (nbytes-n)*8, + ENTROPY_BITS(&blocking_pool), + ENTROPY_BITS(&input_pool)); if (n == 0) { if (file->f_flags & O_NONBLOCK) { @@ -1185,13 +1311,9 @@ 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, - input_pool.entropy_count >= - random_read_wakeup_thresh); - - DEBUG_ENT("awake\n"); + ENTROPY_BITS(&input_pool) >= + random_read_wakeup_thresh); if (signal_pending(current)) { retval = -ERESTARTSYS; @@ -1214,7 +1336,18 @@ 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) { - return extract_entropy_user(&nonblocking_pool, buf, nbytes); + 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; } static unsigned int @@ -1225,9 +1358,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 (input_pool.entropy_count >= random_read_wakeup_thresh) + if (ENTROPY_BITS(&input_pool) >= random_read_wakeup_thresh) mask |= POLLIN | POLLRDNORM; - if (input_pool.entropy_count < random_write_wakeup_thresh) + if (ENTROPY_BITS(&input_pool) < random_write_wakeup_thresh) mask |= POLLOUT | POLLWRNORM; return mask; } @@ -1278,7 +1411,8 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg) switch (cmd) { case RNDGETENTCNT: /* inherently racy, no point locking */ - if (put_user(input_pool.entropy_count, p)) + ent_count = ENTROPY_BITS(&input_pool); + if (put_user(ent_count, p)) return -EFAULT; return 0; case RNDADDTOENTCNT: @@ -1286,7 +1420,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(&input_pool, ent_count); + credit_entropy_bits_safe(&input_pool, ent_count); return 0; case RNDADDENTROPY: if (!capable(CAP_SYS_ADMIN)) @@ -1301,14 +1435,19 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg) size); if (retval < 0) return retval; - credit_entropy_bits(&input_pool, ent_count); + credit_entropy_bits_safe(&input_pool, ent_count); return 0; case RNDZAPENTCNT: case RNDCLEARPOOL: - /* Clear the entropy pool counters. */ + /* + * Clear the entropy pool counters. We no longer clear + * the entropy pool, as that's silly. + */ if (!capable(CAP_SYS_ADMIN)) return -EPERM; - rand_initialize(); + input_pool.entropy_count = 0; + nonblocking_pool.entropy_count = 0; + blocking_pool.entropy_count = 0; return 0; default: return -EINVAL; @@ -1408,6 +1547,23 @@ 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[] = { @@ -1422,7 +1578,7 @@ struct ctl_table random_table[] = { .procname = "entropy_avail", .maxlen = sizeof(int), .mode = 0444, - .proc_handler = proc_dointvec, + .proc_handler = proc_do_entropy, .data = &input_pool.entropy_count, }, { @@ -1444,6 +1600,13 @@ 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, @@ -1462,12 +1625,11 @@ struct ctl_table random_table[] = { static u32 random_int_secret[MD5_MESSAGE_BYTES / 4] ____cacheline_aligned; -static int __init random_int_secret_init(void) +int random_int_secret_init(void) { get_random_bytes(random_int_secret, sizeof(random_int_secret)); return 0; } -late_initcall(random_int_secret_init); /* * Get a random word for internal kernel use only. Similar to urandom but @@ -1486,7 +1648,7 @@ unsigned int get_random_int(void) hash = get_cpu_var(get_random_int_hash); - hash[0] += current->pid + jiffies + get_cycles(); + hash[0] += current->pid + jiffies + random_get_entropy(); md5_transform(hash, random_int_secret); ret = hash[0]; put_cpu_var(get_random_int_hash); diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index c0cbbd429bdc..35259961cc38 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 IRQF_DISABLED set, + * A very tiny interrupt handler. It runs with interrupts disabled, * 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,8 +1040,7 @@ no_irq: rtc_int_handler_ptr = rtc_interrupt; } - if (request_irq(RTC_IRQ, rtc_int_handler_ptr, IRQF_DISABLED, - "rtc", NULL)) { + if (request_irq(RTC_IRQ, rtc_int_handler_ptr, 0, "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 5816b39ff5a9..8bab59292a0d 100644 --- a/drivers/char/snsc.c +++ b/drivers/char/snsc.c @@ -108,8 +108,7 @@ 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 | IRQF_DISABLED, - SYSCTL_BASENAME, sd); + IRQF_SHARED, 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 ee156948b9f8..59bcefd6ec7c 100644 --- a/drivers/char/snsc_event.c +++ b/drivers/char/snsc_event.c @@ -292,8 +292,7 @@ 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 | IRQF_DISABLED, - "system controller events", event_sd); + IRQF_SHARED, "system controller events", event_sd); if (rv) { printk(KERN_WARNING "%s: irq request failed (%d)\n", __func__, rv); diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index bf2349dbbf7f..7cc1fe2241fd 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -876,11 +876,6 @@ found: if (useinput) sonypi_report_input_event(event); -#ifdef CONFIG_ACPI - if (sonypi_acpi_device) - acpi_bus_generate_proc_event(sonypi_acpi_device, 1, event); -#endif - kfifo_in_locked(&sonypi_device.fifo, (unsigned char *)&event, sizeof(event), &sonypi_device.fifo_lock); kill_fasync(&sonypi_device.fifo_async, SIGIO, POLL_IN); diff --git a/drivers/char/tile-srom.c b/drivers/char/tile-srom.c index 7faeb1cde97d..0e506bad1986 100644 --- a/drivers/char/tile-srom.c +++ b/drivers/char/tile-srom.c @@ -279,33 +279,37 @@ loff_t srom_llseek(struct file *file, loff_t offset, int origin) return fixed_size_llseek(file, offset, origin, srom->total_size); } -static ssize_t total_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t total_size_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct srom_dev *srom = dev_get_drvdata(dev); return sprintf(buf, "%u\n", srom->total_size); } +static DEVICE_ATTR_RO(total_size); -static ssize_t sector_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t sector_size_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct srom_dev *srom = dev_get_drvdata(dev); return sprintf(buf, "%u\n", srom->sector_size); } +static DEVICE_ATTR_RO(sector_size); -static ssize_t page_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t page_size_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct srom_dev *srom = dev_get_drvdata(dev); return sprintf(buf, "%u\n", srom->page_size); } +static DEVICE_ATTR_RO(page_size); -static struct device_attribute srom_dev_attrs[] = { - __ATTR(total_size, S_IRUGO, total_show, NULL), - __ATTR(sector_size, S_IRUGO, sector_show, NULL), - __ATTR(page_size, S_IRUGO, page_show, NULL), - __ATTR_NULL +static struct attribute *srom_dev_attrs[] = { + &dev_attr_total_size.attr, + &dev_attr_sector_size.attr, + &dev_attr_page_size.attr, + NULL, }; +ATTRIBUTE_GROUPS(srom_dev); static char *srom_devnode(struct device *dev, umode_t *mode) { @@ -349,7 +353,7 @@ static int srom_setup_minor(struct srom_dev *srom, int index) dev = device_create(srom_class, &platform_bus, MKDEV(srom_major, index), srom, "%d", index); - return PTR_RET(dev); + return PTR_ERR_OR_ZERO(dev); } /** srom_init() - Initialize the driver's module. */ @@ -418,7 +422,7 @@ static int srom_init(void) result = PTR_ERR(srom_class); goto fail_cdev; } - srom_class->dev_attrs = srom_dev_attrs; + srom_class->dev_groups = srom_dev_groups; srom_class->devnode = srom_devnode; /* Do per-partition initialization */ diff --git a/drivers/char/tlclk.c b/drivers/char/tlclk.c index e95e0ab0bd87..100cd1de9939 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, - IRQF_DISABLED, "telco_clock", tlclk_interrupt); + 0, "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 dbfd56446c31..94c0c74434ea 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -91,4 +91,16 @@ config TCG_ST33_I2C 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" + depends on TCG_TPM && XEN + select XEN_XENBUS_FRONTEND + ---help--- + If you want to make TPM support available to a Xen user domain, + say Yes and it will be accessible from within Linux. See + the manpages for xl, xl.conf, and docs/misc/vtpm.txt in + the Xen source repository for more details. + To compile this driver as a module, choose M here; the module + will be called xen-tpmfront. + endif # TCG_TPM diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile index a3736c97c65a..eb41ff97d0ad 100644 --- a/drivers/char/tpm/Makefile +++ b/drivers/char/tpm/Makefile @@ -18,3 +18,4 @@ obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o obj-$(CONFIG_TCG_IBMVTPM) += tpm_ibmvtpm.o obj-$(CONFIG_TCG_ST33_I2C) += tpm_i2c_stm_st33.o +obj-$(CONFIG_TCG_XEN) += xen-tpmfront.o diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 4519cb332987..5796d0157ce0 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -766,6 +766,25 @@ static void tpm_tis_reenable_interrupts(struct tpm_chip *chip) } #endif +#ifdef CONFIG_PM_SLEEP +static int tpm_tis_resume(struct device *dev) +{ + struct tpm_chip *chip = dev_get_drvdata(dev); + int ret; + + if (chip->vendor.irq) + tpm_tis_reenable_interrupts(chip); + + ret = tpm_pm_resume(dev); + if (!ret) + tpm_do_selftest(chip); + + return ret; +} +#endif + +static SIMPLE_DEV_PM_OPS(tpm_tis_pm, tpm_pm_suspend, tpm_tis_resume); + #ifdef CONFIG_PNP static int tpm_tis_pnp_init(struct pnp_dev *pnp_dev, const struct pnp_device_id *pnp_id) @@ -787,26 +806,6 @@ static int tpm_tis_pnp_init(struct pnp_dev *pnp_dev, return tpm_tis_init(&pnp_dev->dev, start, len, irq); } -static int tpm_tis_pnp_suspend(struct pnp_dev *dev, pm_message_t msg) -{ - return tpm_pm_suspend(&dev->dev); -} - -static int tpm_tis_pnp_resume(struct pnp_dev *dev) -{ - struct tpm_chip *chip = pnp_get_drvdata(dev); - int ret; - - if (chip->vendor.irq) - tpm_tis_reenable_interrupts(chip); - - ret = tpm_pm_resume(&dev->dev); - if (!ret) - tpm_do_selftest(chip); - - return ret; -} - static struct pnp_device_id tpm_pnp_tbl[] = { {"PNP0C31", 0}, /* TPM */ {"ATM1200", 0}, /* Atmel */ @@ -835,9 +834,12 @@ static struct pnp_driver tis_pnp_driver = { .name = "tpm_tis", .id_table = tpm_pnp_tbl, .probe = tpm_tis_pnp_init, - .suspend = tpm_tis_pnp_suspend, - .resume = tpm_tis_pnp_resume, .remove = tpm_tis_pnp_remove, +#ifdef CONFIG_PM_SLEEP + .driver = { + .pm = &tpm_tis_pm, + }, +#endif }; #define TIS_HID_USR_IDX sizeof(tpm_pnp_tbl)/sizeof(struct pnp_device_id) -2 @@ -846,20 +848,6 @@ module_param_string(hid, tpm_pnp_tbl[TIS_HID_USR_IDX].id, MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe"); #endif -#ifdef CONFIG_PM_SLEEP -static int tpm_tis_resume(struct device *dev) -{ - struct tpm_chip *chip = dev_get_drvdata(dev); - - if (chip->vendor.irq) - tpm_tis_reenable_interrupts(chip); - - return tpm_pm_resume(dev); -} -#endif - -static SIMPLE_DEV_PM_OPS(tpm_tis_pm, tpm_pm_suspend, tpm_tis_resume); - static struct platform_driver tis_drv = { .driver = { .name = "tpm_tis", diff --git a/drivers/char/tpm/xen-tpmfront.c b/drivers/char/tpm/xen-tpmfront.c new file mode 100644 index 000000000000..94c280d36e8b --- /dev/null +++ b/drivers/char/tpm/xen-tpmfront.c @@ -0,0 +1,438 @@ +/* + * Implementation of the Xen vTPM device frontend + * + * Author: Daniel De Graaf <dgdegra@tycho.nsa.gov> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + */ +#include <linux/errno.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <xen/xen.h> +#include <xen/events.h> +#include <xen/interface/io/tpmif.h> +#include <xen/grant_table.h> +#include <xen/xenbus.h> +#include <xen/page.h> +#include "tpm.h" + +struct tpm_private { + struct tpm_chip *chip; + struct xenbus_device *dev; + + struct vtpm_shared_page *shr; + + unsigned int evtchn; + int ring_ref; + domid_t backend_id; +}; + +enum status_bits { + VTPM_STATUS_RUNNING = 0x1, + VTPM_STATUS_IDLE = 0x2, + VTPM_STATUS_RESULT = 0x4, + VTPM_STATUS_CANCELED = 0x8, +}; + +static u8 vtpm_status(struct tpm_chip *chip) +{ + struct tpm_private *priv = TPM_VPRIV(chip); + switch (priv->shr->state) { + case VTPM_STATE_IDLE: + return VTPM_STATUS_IDLE | VTPM_STATUS_CANCELED; + case VTPM_STATE_FINISH: + return VTPM_STATUS_IDLE | VTPM_STATUS_RESULT; + case VTPM_STATE_SUBMIT: + case VTPM_STATE_CANCEL: /* cancel requested, not yet canceled */ + return VTPM_STATUS_RUNNING; + default: + return 0; + } +} + +static bool vtpm_req_canceled(struct tpm_chip *chip, u8 status) +{ + return status & VTPM_STATUS_CANCELED; +} + +static void vtpm_cancel(struct tpm_chip *chip) +{ + struct tpm_private *priv = TPM_VPRIV(chip); + priv->shr->state = VTPM_STATE_CANCEL; + wmb(); + notify_remote_via_evtchn(priv->evtchn); +} + +static unsigned int shr_data_offset(struct vtpm_shared_page *shr) +{ + return sizeof(*shr) + sizeof(u32) * shr->nr_extra_pages; +} + +static int vtpm_send(struct tpm_chip *chip, u8 *buf, size_t count) +{ + struct tpm_private *priv = TPM_VPRIV(chip); + struct vtpm_shared_page *shr = priv->shr; + unsigned int offset = shr_data_offset(shr); + + u32 ordinal; + unsigned long duration; + + if (offset > PAGE_SIZE) + return -EINVAL; + + if (offset + count > PAGE_SIZE) + return -EINVAL; + + /* Wait for completion of any existing command or cancellation */ + if (wait_for_tpm_stat(chip, VTPM_STATUS_IDLE, chip->vendor.timeout_c, + &chip->vendor.read_queue, true) < 0) { + vtpm_cancel(chip); + return -ETIME; + } + + memcpy(offset + (u8 *)shr, buf, count); + shr->length = count; + barrier(); + shr->state = VTPM_STATE_SUBMIT; + wmb(); + notify_remote_via_evtchn(priv->evtchn); + + ordinal = be32_to_cpu(((struct tpm_input_header*)buf)->ordinal); + duration = tpm_calc_ordinal_duration(chip, ordinal); + + if (wait_for_tpm_stat(chip, VTPM_STATUS_IDLE, duration, + &chip->vendor.read_queue, true) < 0) { + /* got a signal or timeout, try to cancel */ + vtpm_cancel(chip); + return -ETIME; + } + + return count; +} + +static int vtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count) +{ + struct tpm_private *priv = TPM_VPRIV(chip); + struct vtpm_shared_page *shr = priv->shr; + unsigned int offset = shr_data_offset(shr); + size_t length = shr->length; + + if (shr->state == VTPM_STATE_IDLE) + return -ECANCELED; + + /* In theory the wait at the end of _send makes this one unnecessary */ + if (wait_for_tpm_stat(chip, VTPM_STATUS_RESULT, chip->vendor.timeout_c, + &chip->vendor.read_queue, true) < 0) { + vtpm_cancel(chip); + return -ETIME; + } + + if (offset > PAGE_SIZE) + return -EIO; + + if (offset + length > PAGE_SIZE) + length = PAGE_SIZE - offset; + + if (length > count) + length = count; + + memcpy(buf, offset + (u8 *)shr, length); + + return length; +} + +static const struct file_operations vtpm_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 *vtpm_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 vtpm_attr_grp = { + .attrs = vtpm_attrs, +}; + +static const struct tpm_vendor_specific tpm_vtpm = { + .status = vtpm_status, + .recv = vtpm_recv, + .send = vtpm_send, + .cancel = vtpm_cancel, + .req_complete_mask = VTPM_STATUS_IDLE | VTPM_STATUS_RESULT, + .req_complete_val = VTPM_STATUS_IDLE | VTPM_STATUS_RESULT, + .req_canceled = vtpm_req_canceled, + .attr_group = &vtpm_attr_grp, + .miscdev = { + .fops = &vtpm_ops, + }, +}; + +static irqreturn_t tpmif_interrupt(int dummy, void *dev_id) +{ + struct tpm_private *priv = dev_id; + + switch (priv->shr->state) { + case VTPM_STATE_IDLE: + case VTPM_STATE_FINISH: + wake_up_interruptible(&priv->chip->vendor.read_queue); + break; + case VTPM_STATE_SUBMIT: + case VTPM_STATE_CANCEL: + default: + break; + } + return IRQ_HANDLED; +} + +static int setup_chip(struct device *dev, struct tpm_private *priv) +{ + struct tpm_chip *chip; + + chip = tpm_register_hardware(dev, &tpm_vtpm); + if (!chip) + return -ENODEV; + + init_waitqueue_head(&chip->vendor.read_queue); + + priv->chip = chip; + TPM_VPRIV(chip) = priv; + + return 0; +} + +/* caller must clean up in case of errors */ +static int setup_ring(struct xenbus_device *dev, struct tpm_private *priv) +{ + struct xenbus_transaction xbt; + const char *message = NULL; + int rv; + + priv->shr = (void *)__get_free_page(GFP_KERNEL|__GFP_ZERO); + if (!priv->shr) { + xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring"); + return -ENOMEM; + } + + rv = xenbus_grant_ring(dev, virt_to_mfn(priv->shr)); + if (rv < 0) + return rv; + + priv->ring_ref = rv; + + rv = xenbus_alloc_evtchn(dev, &priv->evtchn); + if (rv) + return rv; + + rv = bind_evtchn_to_irqhandler(priv->evtchn, tpmif_interrupt, 0, + "tpmif", priv); + if (rv <= 0) { + xenbus_dev_fatal(dev, rv, "allocating TPM irq"); + return rv; + } + priv->chip->vendor.irq = rv; + + again: + rv = xenbus_transaction_start(&xbt); + if (rv) { + xenbus_dev_fatal(dev, rv, "starting transaction"); + return rv; + } + + rv = xenbus_printf(xbt, dev->nodename, + "ring-ref", "%u", priv->ring_ref); + if (rv) { + message = "writing ring-ref"; + goto abort_transaction; + } + + rv = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", + priv->evtchn); + if (rv) { + message = "writing event-channel"; + goto abort_transaction; + } + + rv = xenbus_printf(xbt, dev->nodename, "feature-protocol-v2", "1"); + if (rv) { + message = "writing feature-protocol-v2"; + goto abort_transaction; + } + + rv = xenbus_transaction_end(xbt, 0); + if (rv == -EAGAIN) + goto again; + if (rv) { + xenbus_dev_fatal(dev, rv, "completing transaction"); + return rv; + } + + xenbus_switch_state(dev, XenbusStateInitialised); + + return 0; + + abort_transaction: + xenbus_transaction_end(xbt, 1); + if (message) + xenbus_dev_error(dev, rv, "%s", message); + + return rv; +} + +static void ring_free(struct tpm_private *priv) +{ + if (!priv) + return; + + if (priv->ring_ref) + gnttab_end_foreign_access(priv->ring_ref, 0, + (unsigned long)priv->shr); + else + free_page((unsigned long)priv->shr); + + if (priv->chip && priv->chip->vendor.irq) + unbind_from_irqhandler(priv->chip->vendor.irq, priv); + + kfree(priv); +} + +static int tpmfront_probe(struct xenbus_device *dev, + const struct xenbus_device_id *id) +{ + struct tpm_private *priv; + int rv; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) { + xenbus_dev_fatal(dev, -ENOMEM, "allocating priv structure"); + return -ENOMEM; + } + + rv = setup_chip(&dev->dev, priv); + if (rv) { + kfree(priv); + return rv; + } + + rv = setup_ring(dev, priv); + if (rv) { + tpm_remove_hardware(&dev->dev); + ring_free(priv); + return rv; + } + + tpm_get_timeouts(priv->chip); + + dev_set_drvdata(&dev->dev, priv->chip); + + return rv; +} + +static int tpmfront_remove(struct xenbus_device *dev) +{ + struct tpm_chip *chip = dev_get_drvdata(&dev->dev); + struct tpm_private *priv = TPM_VPRIV(chip); + tpm_remove_hardware(&dev->dev); + ring_free(priv); + TPM_VPRIV(chip) = NULL; + return 0; +} + +static int tpmfront_resume(struct xenbus_device *dev) +{ + /* A suspend/resume/migrate will interrupt a vTPM anyway */ + tpmfront_remove(dev); + return tpmfront_probe(dev, NULL); +} + +static void backend_changed(struct xenbus_device *dev, + enum xenbus_state backend_state) +{ + int val; + + switch (backend_state) { + case XenbusStateInitialised: + case XenbusStateConnected: + if (dev->state == XenbusStateConnected) + break; + + if (xenbus_scanf(XBT_NIL, dev->otherend, + "feature-protocol-v2", "%d", &val) < 0) + val = 0; + if (!val) { + xenbus_dev_fatal(dev, -EINVAL, + "vTPM protocol 2 required"); + return; + } + xenbus_switch_state(dev, XenbusStateConnected); + break; + + case XenbusStateClosing: + case XenbusStateClosed: + device_unregister(&dev->dev); + xenbus_frontend_closed(dev); + break; + default: + break; + } +} + +static const struct xenbus_device_id tpmfront_ids[] = { + { "vtpm" }, + { "" } +}; +MODULE_ALIAS("xen:vtpm"); + +static DEFINE_XENBUS_DRIVER(tpmfront, , + .probe = tpmfront_probe, + .remove = tpmfront_remove, + .resume = tpmfront_resume, + .otherend_changed = backend_changed, + ); + +static int __init xen_tpmfront_init(void) +{ + if (!xen_domain()) + return -ENODEV; + + return xenbus_register_frontend(&tpmfront_driver); +} +module_init(xen_tpmfront_init); + +static void __exit xen_tpmfront_exit(void) +{ + xenbus_unregister_driver(&tpmfront_driver); +} +module_exit(xen_tpmfront_exit); + +MODULE_AUTHOR("Daniel De Graaf <dgdegra@tycho.nsa.gov>"); +MODULE_DESCRIPTION("Xen vTPM Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index fc45567ad3ac..feea87cc6b8f 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -577,7 +577,8 @@ 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)) + while (!virtqueue_get_buf(vq, &len) + && !virtqueue_is_broken(vq)) cpu_relax(); } spin_unlock(&portdev->c_ovq_lock); @@ -650,7 +651,8 @@ 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)) + while (!virtqueue_get_buf(out_vq, &len) + && !virtqueue_is_broken(out_vq)) cpu_relax(); done: spin_unlock_irqrestore(&port->outvq_lock, flags); @@ -1529,18 +1531,22 @@ static void remove_port_data(struct port *port) { struct port_buffer *buf; + spin_lock_irq(&port->inbuf_lock); /* Remove unused data this port might have received. */ discard_port_data(port); - reclaim_consumed_buffers(port); - /* Remove buffers we queued up for the Host to send us data in. */ while ((buf = virtqueue_detach_unused_buf(port->in_vq))) free_buf(buf, true); + spin_unlock_irq(&port->inbuf_lock); + + spin_lock_irq(&port->outvq_lock); + reclaim_consumed_buffers(port); /* Free pending buffers from the out-queue. */ while ((buf = virtqueue_detach_unused_buf(port->out_vq))) free_buf(buf, true); + spin_unlock_irq(&port->outvq_lock); } /* @@ -1554,6 +1560,7 @@ static void unplug_port(struct port *port) list_del(&port->list); spin_unlock_irq(&port->portdev->ports_lock); + spin_lock_irq(&port->inbuf_lock); if (port->guest_connected) { /* Let the app know the port is going down. */ send_sigio_to_port(port); @@ -1564,6 +1571,7 @@ static void unplug_port(struct port *port) wake_up_interruptible(&port->waitqueue); } + spin_unlock_irq(&port->inbuf_lock); if (is_console_port(port)) { spin_lock_irq(&pdrvdata_lock); @@ -1585,9 +1593,8 @@ static void unplug_port(struct port *port) device_destroy(pdrvdata.class, port->dev->devt); cdev_del(port->cdev); - kfree(port->name); - debugfs_remove(port->debugfs_file); + kfree(port->name); /* * Locks around here are not necessary - a port can't be @@ -1681,7 +1688,9 @@ static void handle_control_message(struct ports_device *portdev, * If the guest is connected, it'll be interested in * knowing the host connection state changed. */ + spin_lock_irq(&port->inbuf_lock); send_sigio_to_port(port); + spin_unlock_irq(&port->inbuf_lock); break; case VIRTIO_CONSOLE_PORT_NAME: /* @@ -1801,13 +1810,13 @@ static void in_intr(struct virtqueue *vq) if (!port->guest_connected && !is_rproc_serial(port->portdev->vdev)) discard_port_data(port); + /* Send a SIGIO indicating new data in case the process asked for it */ + send_sigio_to_port(port); + spin_unlock_irqrestore(&port->inbuf_lock, flags); wake_up_interruptible(&port->waitqueue); - /* Send a SIGIO indicating new data in case the process asked for it */ - send_sigio_to_port(port); - if (is_console_port(port) && hvc_poll(port->cons.hvc)) hvc_kick(); } @@ -1830,12 +1839,8 @@ static void config_intr(struct virtio_device *vdev) struct port *port; u16 rows, cols; - 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)); + virtio_cread(vdev, struct virtio_console_config, cols, &cols); + virtio_cread(vdev, struct virtio_console_config, rows, &rows); port = find_port_by_id(portdev, 0); set_console_size(port, rows, cols); @@ -2007,10 +2012,9 @@ 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_config_val(vdev, VIRTIO_CONSOLE_F_MULTIPORT, - offsetof(struct virtio_console_config, - max_nr_ports), - &portdev->config.max_nr_ports) == 0) { + virtio_cread_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT, + struct virtio_console_config, max_nr_ports, + &portdev->config.max_nr_ports) == 0) { multiport = true; } @@ -2135,7 +2139,7 @@ static struct virtio_device_id rproc_serial_id_table[] = { static unsigned int rproc_serial_features[] = { }; -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int virtcons_freeze(struct virtio_device *vdev) { struct ports_device *portdev; @@ -2213,7 +2217,7 @@ static struct virtio_driver virtio_console = { .probe = virtcons_probe, .remove = virtcons_remove, .config_changed = config_intr, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP .freeze = virtcons_freeze, .restore = virtcons_restore, #endif @@ -2241,10 +2245,8 @@ static int __init init(void) } pdrvdata.debugfs_dir = debugfs_create_dir("virtio-ports", NULL); - if (!pdrvdata.debugfs_dir) { - pr_warning("Error %ld creating debugfs dir for virtio-ports\n", - PTR_ERR(pdrvdata.debugfs_dir)); - } + if (!pdrvdata.debugfs_dir) + pr_warning("Error creating debugfs dir for virtio-ports\n"); INIT_LIST_HEAD(&pdrvdata.consoles); INIT_LIST_HEAD(&pdrvdata.portdevs); diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c index 5224da5202d3..f6345f932e46 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 = (struct hwicap_drvdata *)dev_get_drvdata(dev); + drvdata = dev_get_drvdata(dev); if (!drvdata) return 0; @@ -731,7 +731,6 @@ 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; |