diff options
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/Kconfig | 6 | ||||
-rw-r--r-- | drivers/char/Makefile | 1 | ||||
-rw-r--r-- | drivers/char/agp/intel-gtt.c | 58 | ||||
-rw-r--r-- | drivers/char/apm-emulation.c | 2 | ||||
-rw-r--r-- | drivers/char/hw_random/Kconfig | 2 | ||||
-rw-r--r-- | drivers/char/hw_random/iproc-rng200.c | 9 | ||||
-rw-r--r-- | drivers/char/hw_random/s390-trng.c | 9 | ||||
-rw-r--r-- | drivers/char/hw_random/via-rng.c | 2 | ||||
-rw-r--r-- | drivers/char/random.c | 55 | ||||
-rw-r--r-- | drivers/char/tb0219.c | 359 | ||||
-rw-r--r-- | drivers/char/tpm/Kconfig | 12 | ||||
-rw-r--r-- | drivers/char/tpm/Makefile | 1 | ||||
-rw-r--r-- | drivers/char/tpm/tpm.h | 1 | ||||
-rw-r--r-- | drivers/char/tpm/tpm1-cmd.c | 7 | ||||
-rw-r--r-- | drivers/char/tpm/tpm2-cmd.c | 6 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_tis_core.c | 14 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_tis_core.h | 10 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_tis_i2c.c | 390 |
18 files changed, 509 insertions, 435 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 0b6c03643ddc..0f378d29dab0 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -247,11 +247,6 @@ config SONYPI To compile this driver as a module, choose M here: the module will be called sonypi. -config GPIO_TB0219 - tristate "TANBAC TB0219 GPIO support" - depends on TANBAC_TB022X - select GPIO_VR41XX - source "drivers/char/pcmcia/Kconfig" config MWAVE @@ -431,7 +426,6 @@ config ADI config RANDOM_TRUST_CPU bool "Initialize RNG using CPU RNG instructions" default y - depends on ARCH_RANDOM help Initialize the RNG using random numbers supplied by the CPU's RNG instructions (e.g. RDRAND), if supported and available. These diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 264eb398fdd4..1b35d1724565 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -31,7 +31,6 @@ obj-$(CONFIG_NWFLASH) += nwflash.o obj-$(CONFIG_SCx200_GPIO) += scx200_gpio.o obj-$(CONFIG_PC8736x_GPIO) += pc8736x_gpio.o obj-$(CONFIG_NSC_GPIO) += nsc_gpio.o -obj-$(CONFIG_GPIO_TB0219) += tb0219.o obj-$(CONFIG_TELCLOCK) += tlclk.o obj-$(CONFIG_MWAVE) += mwave/ diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index cfcb450e9b59..bf6716ff863b 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -741,7 +741,7 @@ static void i830_write_entry(dma_addr_t addr, unsigned int entry, writel_relaxed(addr | pte_flags, intel_private.gtt + entry); } -bool intel_enable_gtt(void) +bool intel_gmch_enable_gtt(void) { u8 __iomem *reg; @@ -784,7 +784,7 @@ bool intel_enable_gtt(void) return true; } -EXPORT_SYMBOL(intel_enable_gtt); +EXPORT_SYMBOL(intel_gmch_enable_gtt); static int i830_setup(void) { @@ -818,8 +818,8 @@ static int intel_fake_agp_free_gatt_table(struct agp_bridge_data *bridge) static int intel_fake_agp_configure(void) { - if (!intel_enable_gtt()) - return -EIO; + if (!intel_gmch_enable_gtt()) + return -EIO; intel_private.clear_fake_agp = true; agp_bridge->gart_bus_addr = intel_private.gma_bus_addr; @@ -841,20 +841,20 @@ static bool i830_check_flags(unsigned int flags) return false; } -void intel_gtt_insert_page(dma_addr_t addr, - unsigned int pg, - unsigned int flags) +void intel_gmch_gtt_insert_page(dma_addr_t addr, + unsigned int pg, + unsigned int flags) { intel_private.driver->write_entry(addr, pg, flags); readl(intel_private.gtt + pg); if (intel_private.driver->chipset_flush) intel_private.driver->chipset_flush(); } -EXPORT_SYMBOL(intel_gtt_insert_page); +EXPORT_SYMBOL(intel_gmch_gtt_insert_page); -void intel_gtt_insert_sg_entries(struct sg_table *st, - unsigned int pg_start, - unsigned int flags) +void intel_gmch_gtt_insert_sg_entries(struct sg_table *st, + unsigned int pg_start, + unsigned int flags) { struct scatterlist *sg; unsigned int len, m; @@ -876,13 +876,13 @@ void intel_gtt_insert_sg_entries(struct sg_table *st, if (intel_private.driver->chipset_flush) intel_private.driver->chipset_flush(); } -EXPORT_SYMBOL(intel_gtt_insert_sg_entries); +EXPORT_SYMBOL(intel_gmch_gtt_insert_sg_entries); #if IS_ENABLED(CONFIG_AGP_INTEL) -static void intel_gtt_insert_pages(unsigned int first_entry, - unsigned int num_entries, - struct page **pages, - unsigned int flags) +static void intel_gmch_gtt_insert_pages(unsigned int first_entry, + unsigned int num_entries, + struct page **pages, + unsigned int flags) { int i, j; @@ -902,7 +902,7 @@ static int intel_fake_agp_insert_entries(struct agp_memory *mem, if (intel_private.clear_fake_agp) { int start = intel_private.stolen_size / PAGE_SIZE; int end = intel_private.gtt_mappable_entries; - intel_gtt_clear_range(start, end - start); + intel_gmch_gtt_clear_range(start, end - start); intel_private.clear_fake_agp = false; } @@ -931,12 +931,12 @@ static int intel_fake_agp_insert_entries(struct agp_memory *mem, if (ret != 0) return ret; - intel_gtt_insert_sg_entries(&st, pg_start, type); + intel_gmch_gtt_insert_sg_entries(&st, pg_start, type); mem->sg_list = st.sgl; mem->num_sg = st.nents; } else - intel_gtt_insert_pages(pg_start, mem->page_count, mem->pages, - type); + intel_gmch_gtt_insert_pages(pg_start, mem->page_count, mem->pages, + type); out: ret = 0; @@ -946,7 +946,7 @@ out_err: } #endif -void intel_gtt_clear_range(unsigned int first_entry, unsigned int num_entries) +void intel_gmch_gtt_clear_range(unsigned int first_entry, unsigned int num_entries) { unsigned int i; @@ -956,7 +956,7 @@ void intel_gtt_clear_range(unsigned int first_entry, unsigned int num_entries) } wmb(); } -EXPORT_SYMBOL(intel_gtt_clear_range); +EXPORT_SYMBOL(intel_gmch_gtt_clear_range); #if IS_ENABLED(CONFIG_AGP_INTEL) static int intel_fake_agp_remove_entries(struct agp_memory *mem, @@ -965,7 +965,7 @@ static int intel_fake_agp_remove_entries(struct agp_memory *mem, if (mem->page_count == 0) return 0; - intel_gtt_clear_range(pg_start, mem->page_count); + intel_gmch_gtt_clear_range(pg_start, mem->page_count); if (intel_private.needs_dmar) { intel_gtt_unmap_memory(mem->sg_list, mem->num_sg); @@ -1428,22 +1428,22 @@ int intel_gmch_probe(struct pci_dev *bridge_pdev, struct pci_dev *gpu_pdev, } EXPORT_SYMBOL(intel_gmch_probe); -void intel_gtt_get(u64 *gtt_total, - phys_addr_t *mappable_base, - resource_size_t *mappable_end) +void intel_gmch_gtt_get(u64 *gtt_total, + phys_addr_t *mappable_base, + resource_size_t *mappable_end) { *gtt_total = intel_private.gtt_total_entries << PAGE_SHIFT; *mappable_base = intel_private.gma_bus_addr; *mappable_end = intel_private.gtt_mappable_entries << PAGE_SHIFT; } -EXPORT_SYMBOL(intel_gtt_get); +EXPORT_SYMBOL(intel_gmch_gtt_get); -void intel_gtt_chipset_flush(void) +void intel_gmch_gtt_flush(void) { if (intel_private.driver->chipset_flush) intel_private.driver->chipset_flush(); } -EXPORT_SYMBOL(intel_gtt_chipset_flush); +EXPORT_SYMBOL(intel_gmch_gtt_flush); void intel_gmch_remove(void) { diff --git a/drivers/char/apm-emulation.c b/drivers/char/apm-emulation.c index 230cf852fa9c..e795390b070f 100644 --- a/drivers/char/apm-emulation.c +++ b/drivers/char/apm-emulation.c @@ -544,7 +544,7 @@ static int apm_suspend_notifier(struct notifier_block *nb, wake_up_interruptible(&apm_waitqueue); /* - * Wait for the the suspend_acks_pending variable to drop to + * Wait for the suspend_acks_pending variable to drop to * zero, meaning everybody acked the suspend event (or the * process was killed.) * diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index b3f2d55dc551..3da8e85f8aae 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -87,7 +87,7 @@ config HW_RANDOM_BA431 config HW_RANDOM_BCM2835 tristate "Broadcom BCM2835/BCM63xx Random Number Generator support" depends on ARCH_BCM2835 || ARCH_BCM_NSP || ARCH_BCM_5301X || \ - ARCH_BCM_63XX || BCM63XX || BMIPS_GENERIC || COMPILE_TEST + ARCH_BCMBCA || BCM63XX || BMIPS_GENERIC || COMPILE_TEST default HW_RANDOM help This driver provides kernel-side support for the Random Number diff --git a/drivers/char/hw_random/iproc-rng200.c b/drivers/char/hw_random/iproc-rng200.c index a43743887db1..06bc060534d8 100644 --- a/drivers/char/hw_random/iproc-rng200.c +++ b/drivers/char/hw_random/iproc-rng200.c @@ -1,14 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2015 Broadcom Corporation * -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License as -* published by the Free Software Foundation version 2. -* -* This program is distributed "as is" WITHOUT ANY WARRANTY of any -* kind, whether express or implied; without even the implied warranty -* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. */ /* * DESCRIPTION: The Broadcom iProc RNG200 Driver diff --git a/drivers/char/hw_random/s390-trng.c b/drivers/char/hw_random/s390-trng.c index 2beaa35c0d74..488808dc17a2 100644 --- a/drivers/char/hw_random/s390-trng.c +++ b/drivers/char/hw_random/s390-trng.c @@ -108,7 +108,6 @@ static ssize_t trng_counter_show(struct device *dev, { u64 dev_counter = atomic64_read(&trng_dev_counter); u64 hwrng_counter = atomic64_read(&trng_hwrng_counter); -#if IS_ENABLED(CONFIG_ARCH_RANDOM) u64 arch_counter = atomic64_read(&s390_arch_random_counter); return sysfs_emit(buf, @@ -118,14 +117,6 @@ static ssize_t trng_counter_show(struct device *dev, "total: %llu\n", dev_counter, hwrng_counter, arch_counter, dev_counter + hwrng_counter + arch_counter); -#else - return sysfs_emit(buf, - "trng: %llu\n" - "hwrng: %llu\n" - "total: %llu\n", - dev_counter, hwrng_counter, - dev_counter + hwrng_counter); -#endif } static DEVICE_ATTR(byte_counter, 0444, trng_counter_show, NULL); diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c index 7444cc146e86..a9a0a3b09c8b 100644 --- a/drivers/char/hw_random/via-rng.c +++ b/drivers/char/hw_random/via-rng.c @@ -145,7 +145,7 @@ static int via_rng_init(struct hwrng *rng) } /* Control the RNG via MSR. Tread lightly and pay very close - * close attention to values written, as the reserved fields + * attention to values written, as the reserved fields * are documented to be "undefined and unpredictable"; but it * does not say to write them as zero, so I make a guess that * we restore the values we find in the register. diff --git a/drivers/char/random.c b/drivers/char/random.c index a1af90bacc9f..79d7d4e4e582 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -229,7 +229,7 @@ static void crng_reseed(void) /* * This generates a ChaCha block using the provided key, and then - * immediately overwites that key with half the block. It returns + * immediately overwrites that key with half the block. It returns * the resultant ChaCha state to the user, along with the second * half of the block containing 32 bytes of random data that may * be used; random_data_len may not be greater than 32. @@ -596,12 +596,20 @@ static void extract_entropy(void *buf, size_t len) unsigned long rdseed[32 / sizeof(long)]; size_t counter; } block; - size_t i; + size_t i, longs; - for (i = 0; i < ARRAY_SIZE(block.rdseed); ++i) { - if (!arch_get_random_seed_long(&block.rdseed[i]) && - !arch_get_random_long(&block.rdseed[i])) - block.rdseed[i] = random_get_entropy(); + for (i = 0; i < ARRAY_SIZE(block.rdseed);) { + longs = arch_get_random_seed_longs(&block.rdseed[i], ARRAY_SIZE(block.rdseed) - i); + if (longs) { + i += longs; + continue; + } + longs = arch_get_random_longs(&block.rdseed[i], ARRAY_SIZE(block.rdseed) - i); + if (longs) { + i += longs; + continue; + } + block.rdseed[i++] = random_get_entropy(); } spin_lock_irqsave(&input_pool.lock, flags); @@ -643,10 +651,10 @@ static void __cold _credit_init_bits(size_t bits) add = min_t(size_t, bits, POOL_BITS); + orig = READ_ONCE(input_pool.init_bits); do { - orig = READ_ONCE(input_pool.init_bits); new = min_t(unsigned int, POOL_BITS, orig + add); - } while (cmpxchg(&input_pool.init_bits, orig, new) != orig); + } while (!try_cmpxchg(&input_pool.init_bits, &orig, new)); if (orig < POOL_READY_BITS && new >= POOL_READY_BITS) { crng_reseed(); /* Sets crng_init to CRNG_READY under base_crng.lock. */ @@ -755,8 +763,8 @@ static int random_pm_notification(struct notifier_block *nb, unsigned long actio spin_unlock_irqrestore(&input_pool.lock, flags); if (crng_ready() && (action == PM_RESTORE_PREPARE || - (action == PM_POST_SUSPEND && - !IS_ENABLED(CONFIG_PM_AUTOSLEEP) && !IS_ENABLED(CONFIG_ANDROID)))) { + (action == PM_POST_SUSPEND && !IS_ENABLED(CONFIG_PM_AUTOSLEEP) && + !IS_ENABLED(CONFIG_PM_USERSPACE_AUTOSLEEP)))) { crng_reseed(); pr_notice("crng reseeded on system resumption\n"); } @@ -776,22 +784,31 @@ static struct notifier_block pm_notifier = { .notifier_call = random_pm_notifica int __init random_init(const char *command_line) { ktime_t now = ktime_get_real(); - unsigned int i, arch_bits; - unsigned long entropy; + size_t i, longs, arch_bits; + unsigned long entropy[BLAKE2S_BLOCK_SIZE / sizeof(long)]; #if defined(LATENT_ENTROPY_PLUGIN) static const u8 compiletime_seed[BLAKE2S_BLOCK_SIZE] __initconst __latent_entropy; _mix_pool_bytes(compiletime_seed, sizeof(compiletime_seed)); #endif - for (i = 0, arch_bits = BLAKE2S_BLOCK_SIZE * 8; - i < BLAKE2S_BLOCK_SIZE; i += sizeof(entropy)) { - if (!arch_get_random_seed_long_early(&entropy) && - !arch_get_random_long_early(&entropy)) { - entropy = random_get_entropy(); - arch_bits -= sizeof(entropy) * 8; + for (i = 0, arch_bits = sizeof(entropy) * 8; i < ARRAY_SIZE(entropy);) { + longs = arch_get_random_seed_longs(entropy, ARRAY_SIZE(entropy) - i); + if (longs) { + _mix_pool_bytes(entropy, sizeof(*entropy) * longs); + i += longs; + continue; } - _mix_pool_bytes(&entropy, sizeof(entropy)); + longs = arch_get_random_longs(entropy, ARRAY_SIZE(entropy) - i); + if (longs) { + _mix_pool_bytes(entropy, sizeof(*entropy) * longs); + i += longs; + continue; + } + entropy[0] = random_get_entropy(); + _mix_pool_bytes(entropy, sizeof(*entropy)); + arch_bits -= sizeof(*entropy) * 8; + ++i; } _mix_pool_bytes(&now, sizeof(now)); _mix_pool_bytes(utsname(), sizeof(*(utsname()))); diff --git a/drivers/char/tb0219.c b/drivers/char/tb0219.c deleted file mode 100644 index 1f36be14978f..000000000000 --- a/drivers/char/tb0219.c +++ /dev/null @@ -1,359 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Driver for TANBAC TB0219 base board. - * - * Copyright (C) 2005 Yoichi Yuasa <yuasa@linux-mips.org> - */ -#include <linux/platform_device.h> -#include <linux/fs.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/uaccess.h> - -#include <asm/io.h> -#include <asm/reboot.h> -#include <asm/vr41xx/giu.h> -#include <asm/vr41xx/tb0219.h> - -MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>"); -MODULE_DESCRIPTION("TANBAC TB0219 base board driver"); -MODULE_LICENSE("GPL"); - -static int major; /* default is dynamic major device number */ -module_param(major, int, 0); -MODULE_PARM_DESC(major, "Major device number"); - -static void (*old_machine_restart)(char *command); -static void __iomem *tb0219_base; -static DEFINE_SPINLOCK(tb0219_lock); - -#define tb0219_read(offset) readw(tb0219_base + (offset)) -#define tb0219_write(offset, value) writew((value), tb0219_base + (offset)) - -#define TB0219_START 0x0a000000UL -#define TB0219_SIZE 0x20UL - -#define TB0219_LED 0x00 -#define TB0219_GPIO_INPUT 0x02 -#define TB0219_GPIO_OUTPUT 0x04 -#define TB0219_DIP_SWITCH 0x06 -#define TB0219_MISC 0x08 -#define TB0219_RESET 0x0e -#define TB0219_PCI_SLOT1_IRQ_STATUS 0x10 -#define TB0219_PCI_SLOT2_IRQ_STATUS 0x12 -#define TB0219_PCI_SLOT3_IRQ_STATUS 0x14 - -typedef enum { - TYPE_LED, - TYPE_GPIO_OUTPUT, -} tb0219_type_t; - -/* - * Minor device number - * 0 = 7 segment LED - * - * 16 = GPIO IN 0 - * 17 = GPIO IN 1 - * 18 = GPIO IN 2 - * 19 = GPIO IN 3 - * 20 = GPIO IN 4 - * 21 = GPIO IN 5 - * 22 = GPIO IN 6 - * 23 = GPIO IN 7 - * - * 32 = GPIO OUT 0 - * 33 = GPIO OUT 1 - * 34 = GPIO OUT 2 - * 35 = GPIO OUT 3 - * 36 = GPIO OUT 4 - * 37 = GPIO OUT 5 - * 38 = GPIO OUT 6 - * 39 = GPIO OUT 7 - * - * 48 = DIP switch 1 - * 49 = DIP switch 2 - * 50 = DIP switch 3 - * 51 = DIP switch 4 - * 52 = DIP switch 5 - * 53 = DIP switch 6 - * 54 = DIP switch 7 - * 55 = DIP switch 8 - */ - -static inline char get_led(void) -{ - return (char)tb0219_read(TB0219_LED); -} - -static inline char get_gpio_input_pin(unsigned int pin) -{ - uint16_t values; - - values = tb0219_read(TB0219_GPIO_INPUT); - if (values & (1 << pin)) - return '1'; - - return '0'; -} - -static inline char get_gpio_output_pin(unsigned int pin) -{ - uint16_t values; - - values = tb0219_read(TB0219_GPIO_OUTPUT); - if (values & (1 << pin)) - return '1'; - - return '0'; -} - -static inline char get_dip_switch(unsigned int pin) -{ - uint16_t values; - - values = tb0219_read(TB0219_DIP_SWITCH); - if (values & (1 << pin)) - return '1'; - - return '0'; -} - -static inline int set_led(char command) -{ - tb0219_write(TB0219_LED, command); - - return 0; -} - -static inline int set_gpio_output_pin(unsigned int pin, char command) -{ - unsigned long flags; - uint16_t value; - - if (command != '0' && command != '1') - return -EINVAL; - - spin_lock_irqsave(&tb0219_lock, flags); - value = tb0219_read(TB0219_GPIO_OUTPUT); - if (command == '0') - value &= ~(1 << pin); - else - value |= 1 << pin; - tb0219_write(TB0219_GPIO_OUTPUT, value); - spin_unlock_irqrestore(&tb0219_lock, flags); - - return 0; - -} - -static ssize_t tanbac_tb0219_read(struct file *file, char __user *buf, size_t len, - loff_t *ppos) -{ - unsigned int minor; - char value; - - minor = iminor(file_inode(file)); - switch (minor) { - case 0: - value = get_led(); - break; - case 16 ... 23: - value = get_gpio_input_pin(minor - 16); - break; - case 32 ... 39: - value = get_gpio_output_pin(minor - 32); - break; - case 48 ... 55: - value = get_dip_switch(minor - 48); - break; - default: - return -EBADF; - } - - if (len <= 0) - return -EFAULT; - - if (put_user(value, buf)) - return -EFAULT; - - return 1; -} - -static ssize_t tanbac_tb0219_write(struct file *file, const char __user *data, - size_t len, loff_t *ppos) -{ - unsigned int minor; - tb0219_type_t type; - size_t i; - int retval = 0; - char c; - - minor = iminor(file_inode(file)); - switch (minor) { - case 0: - type = TYPE_LED; - break; - case 32 ... 39: - type = TYPE_GPIO_OUTPUT; - break; - default: - return -EBADF; - } - - for (i = 0; i < len; i++) { - if (get_user(c, data + i)) - return -EFAULT; - - switch (type) { - case TYPE_LED: - retval = set_led(c); - break; - case TYPE_GPIO_OUTPUT: - retval = set_gpio_output_pin(minor - 32, c); - break; - } - - if (retval < 0) - break; - } - - return i; -} - -static int tanbac_tb0219_open(struct inode *inode, struct file *file) -{ - unsigned int minor; - - minor = iminor(inode); - switch (minor) { - case 0: - case 16 ... 23: - case 32 ... 39: - case 48 ... 55: - return stream_open(inode, file); - default: - break; - } - - return -EBADF; -} - -static int tanbac_tb0219_release(struct inode *inode, struct file *file) -{ - return 0; -} - -static const struct file_operations tb0219_fops = { - .owner = THIS_MODULE, - .read = tanbac_tb0219_read, - .write = tanbac_tb0219_write, - .open = tanbac_tb0219_open, - .release = tanbac_tb0219_release, - .llseek = no_llseek, -}; - -static void tb0219_restart(char *command) -{ - tb0219_write(TB0219_RESET, 0); -} - -static void tb0219_pci_irq_init(void) -{ - /* PCI Slot 1 */ - vr41xx_set_irq_trigger(TB0219_PCI_SLOT1_PIN, IRQ_TRIGGER_LEVEL, IRQ_SIGNAL_THROUGH); - vr41xx_set_irq_level(TB0219_PCI_SLOT1_PIN, IRQ_LEVEL_LOW); - - /* PCI Slot 2 */ - vr41xx_set_irq_trigger(TB0219_PCI_SLOT2_PIN, IRQ_TRIGGER_LEVEL, IRQ_SIGNAL_THROUGH); - vr41xx_set_irq_level(TB0219_PCI_SLOT2_PIN, IRQ_LEVEL_LOW); - - /* PCI Slot 3 */ - vr41xx_set_irq_trigger(TB0219_PCI_SLOT3_PIN, IRQ_TRIGGER_LEVEL, IRQ_SIGNAL_THROUGH); - vr41xx_set_irq_level(TB0219_PCI_SLOT3_PIN, IRQ_LEVEL_LOW); -} - -static int tb0219_probe(struct platform_device *dev) -{ - int retval; - - if (request_mem_region(TB0219_START, TB0219_SIZE, "TB0219") == NULL) - return -EBUSY; - - tb0219_base = ioremap(TB0219_START, TB0219_SIZE); - if (tb0219_base == NULL) { - release_mem_region(TB0219_START, TB0219_SIZE); - return -ENOMEM; - } - - retval = register_chrdev(major, "TB0219", &tb0219_fops); - if (retval < 0) { - iounmap(tb0219_base); - tb0219_base = NULL; - release_mem_region(TB0219_START, TB0219_SIZE); - return retval; - } - - old_machine_restart = _machine_restart; - _machine_restart = tb0219_restart; - - tb0219_pci_irq_init(); - - if (major == 0) { - major = retval; - printk(KERN_INFO "TB0219: major number %d\n", major); - } - - return 0; -} - -static int tb0219_remove(struct platform_device *dev) -{ - _machine_restart = old_machine_restart; - - iounmap(tb0219_base); - tb0219_base = NULL; - - release_mem_region(TB0219_START, TB0219_SIZE); - - return 0; -} - -static struct platform_device *tb0219_platform_device; - -static struct platform_driver tb0219_device_driver = { - .probe = tb0219_probe, - .remove = tb0219_remove, - .driver = { - .name = "TB0219", - }, -}; - -static int __init tanbac_tb0219_init(void) -{ - int retval; - - tb0219_platform_device = platform_device_alloc("TB0219", -1); - if (!tb0219_platform_device) - return -ENOMEM; - - retval = platform_device_add(tb0219_platform_device); - if (retval < 0) { - platform_device_put(tb0219_platform_device); - return retval; - } - - retval = platform_driver_register(&tb0219_device_driver); - if (retval < 0) - platform_device_unregister(tb0219_platform_device); - - return retval; -} - -static void __exit tanbac_tb0219_exit(void) -{ - platform_driver_unregister(&tb0219_device_driver); - platform_device_unregister(tb0219_platform_device); -} - -module_init(tanbac_tb0219_init); -module_exit(tanbac_tb0219_exit); diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index 4a5516406c22..927088b2c3d3 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -74,6 +74,18 @@ config TCG_TIS_SPI_CR50 If you have a H1 secure module running Cr50 firmware on SPI bus, say Yes and it will be accessible from within Linux. +config TCG_TIS_I2C + tristate "TPM Interface Specification 1.3 Interface / TPM 2.0 FIFO Interface - (I2C - generic)" + depends on I2C + select CRC_CCITT + select TCG_TIS_CORE + help + If you have a TPM security chip, compliant with the TCG TPM PTP + (I2C interface) specification and connected to an I2C bus master, + say Yes and it will be accessible from within Linux. + To compile this driver as a module, choose M here; + the module will be called tpm_tis_i2c. + config TCG_TIS_SYNQUACER tristate "TPM Interface Specification 1.2 Interface / TPM 2.0 FIFO Interface (MMIO - SynQuacer)" depends on ARCH_SYNQUACER || COMPILE_TEST diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile index 66d39ea6bd10..0222b1ddb310 100644 --- a/drivers/char/tpm/Makefile +++ b/drivers/char/tpm/Makefile @@ -29,6 +29,7 @@ tpm_tis_spi-$(CONFIG_TCG_TIS_SPI_CR50) += tpm_tis_spi_cr50.o obj-$(CONFIG_TCG_TIS_I2C_CR50) += tpm_tis_i2c_cr50.o +obj-$(CONFIG_TCG_TIS_I2C) += tpm_tis_i2c.o obj-$(CONFIG_TCG_TIS_I2C_ATMEL) += tpm_i2c_atmel.o obj-$(CONFIG_TCG_TIS_I2C_INFINEON) += tpm_i2c_infineon.o obj-$(CONFIG_TCG_TIS_I2C_NUVOTON) += tpm_i2c_nuvoton.o diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 2163c6ee0d36..24ee4e1cc452 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -55,6 +55,7 @@ enum tpm_addr { #define TPM_WARN_DOING_SELFTEST 0x802 #define TPM_ERR_DEACTIVATED 0x6 #define TPM_ERR_DISABLED 0x7 +#define TPM_ERR_FAILEDSELFTEST 0x1C #define TPM_ERR_INVALID_POSTINIT 38 #define TPM_TAG_RQU_COMMAND 193 diff --git a/drivers/char/tpm/tpm1-cmd.c b/drivers/char/tpm/tpm1-cmd.c index f7dc986fa4a0..cf64c7385105 100644 --- a/drivers/char/tpm/tpm1-cmd.c +++ b/drivers/char/tpm/tpm1-cmd.c @@ -709,7 +709,12 @@ int tpm1_auto_startup(struct tpm_chip *chip) if (rc) goto out; rc = tpm1_do_selftest(chip); - if (rc) { + if (rc == TPM_ERR_FAILEDSELFTEST) { + dev_warn(&chip->dev, "TPM self test failed, switching to the firmware upgrade mode\n"); + /* A TPM in this state possibly allows or needs a firmware upgrade */ + chip->flags |= TPM_CHIP_FLAG_FIRMWARE_UPGRADE; + return 0; + } else if (rc) { dev_err(&chip->dev, "TPM self test failed\n"); goto out; } diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index c1eb5d223839..65d03867e114 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -752,6 +752,12 @@ int tpm2_auto_startup(struct tpm_chip *chip) } rc = tpm2_get_cc_attrs_tbl(chip); + if (rc == TPM2_RC_FAILURE || (rc < 0 && rc != -ENOMEM)) { + dev_info(&chip->dev, + "TPM in field failure mode, requires firmware upgrade\n"); + chip->flags |= TPM_CHIP_FLAG_FIRMWARE_UPGRADE; + rc = 0; + } out: /* diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c index dc56b976d816..757623bacfd5 100644 --- a/drivers/char/tpm/tpm_tis_core.c +++ b/drivers/char/tpm/tpm_tis_core.c @@ -289,6 +289,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count) int size = 0; int status; u32 expected; + int rc; if (count < TPM_HEADER_SIZE) { size = -EIO; @@ -328,6 +329,13 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count) goto out; } + rc = tpm_tis_verify_crc(priv, (size_t)size, buf); + if (rc < 0) { + dev_err(&chip->dev, "CRC mismatch for response.\n"); + size = rc; + goto out; + } + out: tpm_tis_ready(chip); return size; @@ -443,6 +451,12 @@ static int tpm_tis_send_main(struct tpm_chip *chip, const u8 *buf, size_t len) if (rc < 0) return rc; + rc = tpm_tis_verify_crc(priv, len, buf); + if (rc < 0) { + dev_err(&chip->dev, "CRC mismatch for command.\n"); + return rc; + } + /* go and do it */ rc = tpm_tis_write8(priv, TPM_STS(priv->locality), TPM_STS_GO); if (rc < 0) diff --git a/drivers/char/tpm/tpm_tis_core.h b/drivers/char/tpm/tpm_tis_core.h index 6c203f36b8a1..66a5a13cd1df 100644 --- a/drivers/char/tpm/tpm_tis_core.h +++ b/drivers/char/tpm/tpm_tis_core.h @@ -121,6 +121,8 @@ struct tpm_tis_phy_ops { u8 *result, enum tpm_tis_io_mode mode); int (*write_bytes)(struct tpm_tis_data *data, u32 addr, u16 len, const u8 *value, enum tpm_tis_io_mode mode); + int (*verify_crc)(struct tpm_tis_data *data, size_t len, + const u8 *value); }; static inline int tpm_tis_read_bytes(struct tpm_tis_data *data, u32 addr, @@ -188,6 +190,14 @@ static inline int tpm_tis_write32(struct tpm_tis_data *data, u32 addr, return rc; } +static inline int tpm_tis_verify_crc(struct tpm_tis_data *data, size_t len, + const u8 *value) +{ + if (!data->phy_ops->verify_crc) + return 0; + return data->phy_ops->verify_crc(data, len, value); +} + static inline bool is_bsw(void) { #ifdef CONFIG_X86 diff --git a/drivers/char/tpm/tpm_tis_i2c.c b/drivers/char/tpm/tpm_tis_i2c.c new file mode 100644 index 000000000000..ba0911b1d1ff --- /dev/null +++ b/drivers/char/tpm/tpm_tis_i2c.c @@ -0,0 +1,390 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2014-2021 Nuvoton Technology corporation + * Copyright (C) 2019-2022 Infineon Technologies AG + * + * This device driver implements the TPM interface as defined in the TCG PC + * Client Platform TPM Profile (PTP) Specification for TPM 2.0 v1.04 + * Revision 14. + * + * It is based on the tpm_tis_spi device driver. + */ + +#include <linux/i2c.h> +#include <linux/crc-ccitt.h> +#include "tpm_tis_core.h" + +/* TPM registers */ +#define TPM_I2C_LOC_SEL 0x00 +#define TPM_I2C_ACCESS 0x04 +#define TPM_I2C_INTERFACE_CAPABILITY 0x30 +#define TPM_I2C_DEVICE_ADDRESS 0x38 +#define TPM_I2C_DATA_CSUM_ENABLE 0x40 +#define TPM_DATA_CSUM 0x44 +#define TPM_I2C_DID_VID 0x48 +#define TPM_I2C_RID 0x4C + +/* TIS-compatible register address to avoid clash with TPM_ACCESS (0x00) */ +#define TPM_LOC_SEL 0x0FFF + +/* Mask to extract the I2C register from TIS register addresses */ +#define TPM_TIS_REGISTER_MASK 0x0FFF + +/* Default Guard Time of 250µs until interface capability register is read */ +#define GUARD_TIME_DEFAULT_MIN 250 +#define GUARD_TIME_DEFAULT_MAX 300 + +/* Guard Time of 250µs after I2C slave NACK */ +#define GUARD_TIME_ERR_MIN 250 +#define GUARD_TIME_ERR_MAX 300 + +/* Guard Time bit masks; SR is repeated start, RW is read then write, etc. */ +#define TPM_GUARD_TIME_SR_MASK 0x40000000 +#define TPM_GUARD_TIME_RR_MASK 0x00100000 +#define TPM_GUARD_TIME_RW_MASK 0x00080000 +#define TPM_GUARD_TIME_WR_MASK 0x00040000 +#define TPM_GUARD_TIME_WW_MASK 0x00020000 +#define TPM_GUARD_TIME_MIN_MASK 0x0001FE00 +#define TPM_GUARD_TIME_MIN_SHIFT 9 + +/* Masks with bits that must be read zero */ +#define TPM_ACCESS_READ_ZERO 0x48 +#define TPM_INT_ENABLE_ZERO 0x7FFFFF6 +#define TPM_STS_READ_ZERO 0x23 +#define TPM_INTF_CAPABILITY_ZERO 0x0FFFF000 +#define TPM_I2C_INTERFACE_CAPABILITY_ZERO 0x80000000 + +struct tpm_tis_i2c_phy { + struct tpm_tis_data priv; + struct i2c_client *i2c_client; + bool guard_time_read; + bool guard_time_write; + u16 guard_time_min; + u16 guard_time_max; + u8 *io_buf; +}; + +static inline struct tpm_tis_i2c_phy * +to_tpm_tis_i2c_phy(struct tpm_tis_data *data) +{ + return container_of(data, struct tpm_tis_i2c_phy, priv); +} + +/* + * tpm_tis_core uses the register addresses as defined in Table 19 "Allocation + * of Register Space for FIFO TPM Access" of the TCG PC Client PTP + * Specification. In order for this code to work together with tpm_tis_core, + * those addresses need to mapped to the registers defined for I2C TPMs in + * Table 51 "I2C-TPM Register Overview". + * + * For most addresses this can be done by simply stripping off the locality + * information from the address. A few addresses need to be mapped explicitly, + * since the corresponding I2C registers have been moved around. TPM_LOC_SEL is + * only defined for I2C TPMs and is also mapped explicitly here to distinguish + * it from TPM_ACCESS(0). + * + * Locality information is ignored, since this driver assumes exclusive access + * to the TPM and always uses locality 0. + */ +static u8 tpm_tis_i2c_address_to_register(u32 addr) +{ + addr &= TPM_TIS_REGISTER_MASK; + + switch (addr) { + case TPM_ACCESS(0): + return TPM_I2C_ACCESS; + case TPM_LOC_SEL: + return TPM_I2C_LOC_SEL; + case TPM_DID_VID(0): + return TPM_I2C_DID_VID; + case TPM_RID(0): + return TPM_I2C_RID; + default: + return addr; + } +} + +static int tpm_tis_i2c_retry_transfer_until_ack(struct tpm_tis_data *data, + struct i2c_msg *msg) +{ + struct tpm_tis_i2c_phy *phy = to_tpm_tis_i2c_phy(data); + bool guard_time; + int i = 0; + int ret; + + if (msg->flags & I2C_M_RD) + guard_time = phy->guard_time_read; + else + guard_time = phy->guard_time_write; + + do { + ret = i2c_transfer(phy->i2c_client->adapter, msg, 1); + if (ret < 0) + usleep_range(GUARD_TIME_ERR_MIN, GUARD_TIME_ERR_MAX); + else if (guard_time) + usleep_range(phy->guard_time_min, phy->guard_time_max); + /* retry on TPM NACK */ + } while (ret < 0 && i++ < TPM_RETRY); + + return ret; +} + +/* Check that bits which must be read zero are not set */ +static int tpm_tis_i2c_sanity_check_read(u8 reg, u16 len, u8 *buf) +{ + u32 zero_mask; + u32 value; + + switch (len) { + case sizeof(u8): + value = buf[0]; + break; + case sizeof(u16): + value = le16_to_cpup((__le16 *)buf); + break; + case sizeof(u32): + value = le32_to_cpup((__le32 *)buf); + break; + default: + /* unknown length, skip check */ + return 0; + } + + switch (reg) { + case TPM_I2C_ACCESS: + zero_mask = TPM_ACCESS_READ_ZERO; + break; + case TPM_INT_ENABLE(0) & TPM_TIS_REGISTER_MASK: + zero_mask = TPM_INT_ENABLE_ZERO; + break; + case TPM_STS(0) & TPM_TIS_REGISTER_MASK: + zero_mask = TPM_STS_READ_ZERO; + break; + case TPM_INTF_CAPS(0) & TPM_TIS_REGISTER_MASK: + zero_mask = TPM_INTF_CAPABILITY_ZERO; + break; + case TPM_I2C_INTERFACE_CAPABILITY: + zero_mask = TPM_I2C_INTERFACE_CAPABILITY_ZERO; + break; + default: + /* unknown register, skip check */ + return 0; + } + + if (unlikely((value & zero_mask) != 0x00)) { + pr_debug("TPM I2C read of register 0x%02x failed sanity check: 0x%x\n", reg, value); + return -EIO; + } + + return 0; +} + +static int tpm_tis_i2c_read_bytes(struct tpm_tis_data *data, u32 addr, u16 len, + u8 *result, enum tpm_tis_io_mode io_mode) +{ + struct tpm_tis_i2c_phy *phy = to_tpm_tis_i2c_phy(data); + struct i2c_msg msg = { .addr = phy->i2c_client->addr }; + u8 reg = tpm_tis_i2c_address_to_register(addr); + int i; + int ret; + + for (i = 0; i < TPM_RETRY; i++) { + /* write register */ + msg.len = sizeof(reg); + msg.buf = ® + msg.flags = 0; + ret = tpm_tis_i2c_retry_transfer_until_ack(data, &msg); + if (ret < 0) + return ret; + + /* read data */ + msg.buf = result; + msg.len = len; + msg.flags = I2C_M_RD; + ret = tpm_tis_i2c_retry_transfer_until_ack(data, &msg); + if (ret < 0) + return ret; + + ret = tpm_tis_i2c_sanity_check_read(reg, len, result); + if (ret == 0) + return 0; + + usleep_range(GUARD_TIME_ERR_MIN, GUARD_TIME_ERR_MAX); + } + + return ret; +} + +static int tpm_tis_i2c_write_bytes(struct tpm_tis_data *data, u32 addr, u16 len, + const u8 *value, + enum tpm_tis_io_mode io_mode) +{ + struct tpm_tis_i2c_phy *phy = to_tpm_tis_i2c_phy(data); + struct i2c_msg msg = { .addr = phy->i2c_client->addr }; + u8 reg = tpm_tis_i2c_address_to_register(addr); + int ret; + + if (len > TPM_BUFSIZE - 1) + return -EIO; + + /* write register and data in one go */ + phy->io_buf[0] = reg; + memcpy(phy->io_buf + sizeof(reg), value, len); + + msg.len = sizeof(reg) + len; + msg.buf = phy->io_buf; + ret = tpm_tis_i2c_retry_transfer_until_ack(data, &msg); + if (ret < 0) + return ret; + + return 0; +} + +static int tpm_tis_i2c_verify_crc(struct tpm_tis_data *data, size_t len, + const u8 *value) +{ + u16 crc_tpm, crc_host; + int rc; + + rc = tpm_tis_read16(data, TPM_DATA_CSUM, &crc_tpm); + if (rc < 0) + return rc; + + /* reflect crc result, regardless of host endianness */ + crc_host = swab16(crc_ccitt(0, value, len)); + if (crc_tpm != crc_host) + return -EIO; + + return 0; +} + +/* + * Guard Time: + * After each I2C operation, the TPM might require the master to wait. + * The time period is vendor-specific and must be read from the + * TPM_I2C_INTERFACE_CAPABILITY register. + * + * Before the Guard Time is read (or after the TPM failed to send an I2C NACK), + * a Guard Time of 250µs applies. + * + * Various flags in the same register indicate if a guard time is needed: + * - SR: <I2C read with repeated start> <guard time> <I2C read> + * - RR: <I2C read> <guard time> <I2C read> + * - RW: <I2C read> <guard time> <I2C write> + * - WR: <I2C write> <guard time> <I2C read> + * - WW: <I2C write> <guard time> <I2C write> + * + * See TCG PC Client PTP Specification v1.04, 8.1.10 GUARD_TIME + */ +static int tpm_tis_i2c_init_guard_time(struct tpm_tis_i2c_phy *phy) +{ + u32 i2c_caps; + int ret; + + phy->guard_time_read = true; + phy->guard_time_write = true; + phy->guard_time_min = GUARD_TIME_DEFAULT_MIN; + phy->guard_time_max = GUARD_TIME_DEFAULT_MAX; + + ret = tpm_tis_i2c_read_bytes(&phy->priv, TPM_I2C_INTERFACE_CAPABILITY, + sizeof(i2c_caps), (u8 *)&i2c_caps, + TPM_TIS_PHYS_32); + if (ret) + return ret; + + phy->guard_time_read = (i2c_caps & TPM_GUARD_TIME_RR_MASK) || + (i2c_caps & TPM_GUARD_TIME_RW_MASK); + phy->guard_time_write = (i2c_caps & TPM_GUARD_TIME_WR_MASK) || + (i2c_caps & TPM_GUARD_TIME_WW_MASK); + phy->guard_time_min = (i2c_caps & TPM_GUARD_TIME_MIN_MASK) >> + TPM_GUARD_TIME_MIN_SHIFT; + /* guard_time_max = guard_time_min * 1.2 */ + phy->guard_time_max = phy->guard_time_min + phy->guard_time_min / 5; + + return 0; +} + +static SIMPLE_DEV_PM_OPS(tpm_tis_pm, tpm_pm_suspend, tpm_tis_resume); + +static const struct tpm_tis_phy_ops tpm_i2c_phy_ops = { + .read_bytes = tpm_tis_i2c_read_bytes, + .write_bytes = tpm_tis_i2c_write_bytes, + .verify_crc = tpm_tis_i2c_verify_crc, +}; + +static int tpm_tis_i2c_probe(struct i2c_client *dev, + const struct i2c_device_id *id) +{ + struct tpm_tis_i2c_phy *phy; + const u8 crc_enable = 1; + const u8 locality = 0; + int ret; + + phy = devm_kzalloc(&dev->dev, sizeof(struct tpm_tis_i2c_phy), + GFP_KERNEL); + if (!phy) + return -ENOMEM; + + phy->io_buf = devm_kzalloc(&dev->dev, TPM_BUFSIZE, GFP_KERNEL); + if (!phy->io_buf) + return -ENOMEM; + + phy->i2c_client = dev; + + /* must precede all communication with the tpm */ + ret = tpm_tis_i2c_init_guard_time(phy); + if (ret) + return ret; + + ret = tpm_tis_i2c_write_bytes(&phy->priv, TPM_LOC_SEL, sizeof(locality), + &locality, TPM_TIS_PHYS_8); + if (ret) + return ret; + + ret = tpm_tis_i2c_write_bytes(&phy->priv, TPM_I2C_DATA_CSUM_ENABLE, + sizeof(crc_enable), &crc_enable, + TPM_TIS_PHYS_8); + if (ret) + return ret; + + return tpm_tis_core_init(&dev->dev, &phy->priv, -1, &tpm_i2c_phy_ops, + NULL); +} + +static int tpm_tis_i2c_remove(struct i2c_client *client) +{ + struct tpm_chip *chip = i2c_get_clientdata(client); + + tpm_chip_unregister(chip); + tpm_tis_remove(chip); + return 0; +} + +static const struct i2c_device_id tpm_tis_i2c_id[] = { + { "tpm_tis_i2c", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, tpm_tis_i2c_id); + +#ifdef CONFIG_OF +static const struct of_device_id of_tis_i2c_match[] = { + { .compatible = "infineon,slb9673", }, + {} +}; +MODULE_DEVICE_TABLE(of, of_tis_i2c_match); +#endif + +static struct i2c_driver tpm_tis_i2c_driver = { + .driver = { + .name = "tpm_tis_i2c", + .pm = &tpm_tis_pm, + .of_match_table = of_match_ptr(of_tis_i2c_match), + }, + .probe = tpm_tis_i2c_probe, + .remove = tpm_tis_i2c_remove, + .id_table = tpm_tis_i2c_id, +}; +module_i2c_driver(tpm_tis_i2c_driver); + +MODULE_DESCRIPTION("TPM Driver for native I2C access"); +MODULE_LICENSE("GPL"); |