diff options
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/Kconfig | 9 | ||||
-rw-r--r-- | drivers/char/agp/agp.h | 5 | ||||
-rw-r--r-- | drivers/char/agp/generic.c | 11 | ||||
-rw-r--r-- | drivers/char/agp/intel-gtt.c | 14 | ||||
-rw-r--r-- | drivers/char/hw_random/core.c | 215 | ||||
-rw-r--r-- | drivers/char/hw_random/virtio-rng.c | 1 | ||||
-rw-r--r-- | drivers/char/i8k.c | 316 | ||||
-rw-r--r-- | drivers/char/mem.c | 22 | ||||
-rw-r--r-- | drivers/char/tpm/tpm-interface.c | 6 | ||||
-rw-r--r-- | drivers/char/tpm/tpm.h | 5 | ||||
-rw-r--r-- | drivers/char/tpm/tpm2-cmd.c | 59 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_crb.c | 20 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_ibmvtpm.c | 20 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_tis.c | 37 | ||||
-rw-r--r-- | drivers/char/virtio_console.c | 6 |
15 files changed, 483 insertions, 263 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index efefd12a0f7b..a4af8221751e 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -6,6 +6,15 @@ menu "Character devices" source "drivers/tty/Kconfig" +config DEVMEM + bool "/dev/mem virtual device support" + default y + help + Say Y here if you want to support the /dev/mem device. + The /dev/mem device is used to access areas of physical + memory. + When in doubt, say "Y". + config DEVKMEM bool "/dev/kmem virtual device support" default y diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index b709749c8639..4eb1c772ded7 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h @@ -219,7 +219,10 @@ struct agp_bridge_data *agp_generic_find_bridge(struct pci_dev *pdev); /* generic functions for user-populated AGP memory types */ struct agp_memory *agp_generic_alloc_user(size_t page_count, int type); void agp_alloc_page_array(size_t size, struct agp_memory *mem); -void agp_free_page_array(struct agp_memory *mem); +static inline void agp_free_page_array(struct agp_memory *mem) +{ + kvfree(mem->pages); +} /* generic routines for agp>=3 */ diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index 0fbccce1cee9..f002fa5d1887 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c @@ -98,17 +98,6 @@ void agp_alloc_page_array(size_t size, struct agp_memory *mem) } EXPORT_SYMBOL(agp_alloc_page_array); -void agp_free_page_array(struct agp_memory *mem) -{ - if (is_vmalloc_addr(mem->pages)) { - vfree(mem->pages); - } else { - kfree(mem->pages); - } -} -EXPORT_SYMBOL(agp_free_page_array); - - static struct agp_memory *agp_create_user_memory(unsigned long num_agp_pages) { struct agp_memory *new; diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 92aa43fa8d70..0b4188b9af7c 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -225,7 +225,7 @@ static int i810_insert_dcache_entries(struct agp_memory *mem, off_t pg_start, intel_private.driver->write_entry(addr, i, type); } - readl(intel_private.gtt+i-1); + wmb(); return 0; } @@ -329,7 +329,7 @@ static void i810_write_entry(dma_addr_t addr, unsigned int entry, break; } - writel(addr | pte_flags, intel_private.gtt + entry); + writel_relaxed(addr | pte_flags, intel_private.gtt + entry); } static const struct aper_size_info_fixed intel_fake_agp_sizes[] = { @@ -735,7 +735,7 @@ static void i830_write_entry(dma_addr_t addr, unsigned int entry, if (flags == AGP_USER_CACHED_MEMORY) pte_flags |= I830_PTE_SYSTEM_CACHED; - writel(addr | pte_flags, intel_private.gtt + entry); + writel_relaxed(addr | pte_flags, intel_private.gtt + entry); } bool intel_enable_gtt(void) @@ -858,7 +858,7 @@ void intel_gtt_insert_sg_entries(struct sg_table *st, j++; } } - readl(intel_private.gtt+j-1); + wmb(); } EXPORT_SYMBOL(intel_gtt_insert_sg_entries); @@ -875,7 +875,7 @@ static void intel_gtt_insert_pages(unsigned int first_entry, intel_private.driver->write_entry(addr, j, flags); } - readl(intel_private.gtt+j-1); + wmb(); } static int intel_fake_agp_insert_entries(struct agp_memory *mem, @@ -938,7 +938,7 @@ void intel_gtt_clear_range(unsigned int first_entry, unsigned int num_entries) intel_private.driver->write_entry(intel_private.scratch_page_dma, i, 0); } - readl(intel_private.gtt+i-1); + wmb(); } EXPORT_SYMBOL(intel_gtt_clear_range); @@ -1106,7 +1106,7 @@ static void i965_write_entry(dma_addr_t addr, /* Shift high bits down */ addr |= (addr >> 28) & 0xf0; - writel(addr | pte_flags, intel_private.gtt + entry); + writel_relaxed(addr | pte_flags, intel_private.gtt + entry); } static int i9xx_setup(void) diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index 1500cfd799a7..32a8a867f7f8 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c @@ -42,6 +42,7 @@ #include <linux/delay.h> #include <linux/slab.h> #include <linux/random.h> +#include <linux/err.h> #include <asm/uaccess.h> @@ -53,7 +54,10 @@ static struct hwrng *current_rng; static struct task_struct *hwrng_fill; static LIST_HEAD(rng_list); +/* Protects rng_list and current_rng */ static DEFINE_MUTEX(rng_mutex); +/* Protects rng read functions, data_avail, rng_buffer and rng_fillbuf */ +static DEFINE_MUTEX(reading_mutex); static int data_avail; static u8 *rng_buffer, *rng_fillbuf; static unsigned short current_quality; @@ -66,6 +70,8 @@ module_param(default_quality, ushort, 0644); MODULE_PARM_DESC(default_quality, "default entropy content of hwrng per mill"); +static void drop_current_rng(void); +static int hwrng_init(struct hwrng *rng); static void start_khwrngd(void); static inline int rng_get_data(struct hwrng *rng, u8 *buffer, size_t size, @@ -81,13 +87,83 @@ static void add_early_randomness(struct hwrng *rng) unsigned char bytes[16]; int bytes_read; + mutex_lock(&reading_mutex); bytes_read = rng_get_data(rng, bytes, sizeof(bytes), 1); + mutex_unlock(&reading_mutex); if (bytes_read > 0) add_device_randomness(bytes, bytes_read); } -static inline int hwrng_init(struct hwrng *rng) +static inline void cleanup_rng(struct kref *kref) { + struct hwrng *rng = container_of(kref, struct hwrng, ref); + + if (rng->cleanup) + rng->cleanup(rng); + + complete(&rng->cleanup_done); +} + +static int set_current_rng(struct hwrng *rng) +{ + int err; + + BUG_ON(!mutex_is_locked(&rng_mutex)); + + err = hwrng_init(rng); + if (err) + return err; + + drop_current_rng(); + current_rng = rng; + + return 0; +} + +static void drop_current_rng(void) +{ + BUG_ON(!mutex_is_locked(&rng_mutex)); + if (!current_rng) + return; + + /* decrease last reference for triggering the cleanup */ + kref_put(¤t_rng->ref, cleanup_rng); + current_rng = NULL; +} + +/* Returns ERR_PTR(), NULL or refcounted hwrng */ +static struct hwrng *get_current_rng(void) +{ + struct hwrng *rng; + + if (mutex_lock_interruptible(&rng_mutex)) + return ERR_PTR(-ERESTARTSYS); + + rng = current_rng; + if (rng) + kref_get(&rng->ref); + + mutex_unlock(&rng_mutex); + return rng; +} + +static void put_rng(struct hwrng *rng) +{ + /* + * Hold rng_mutex here so we serialize in case they set_current_rng + * on rng again immediately. + */ + mutex_lock(&rng_mutex); + if (rng) + kref_put(&rng->ref, cleanup_rng); + mutex_unlock(&rng_mutex); +} + +static int hwrng_init(struct hwrng *rng) +{ + if (kref_get_unless_zero(&rng->ref)) + goto skip_init; + if (rng->init) { int ret; @@ -95,6 +171,11 @@ static inline int hwrng_init(struct hwrng *rng) if (ret) return ret; } + + kref_init(&rng->ref); + reinit_completion(&rng->cleanup_done); + +skip_init: add_early_randomness(rng); current_quality = rng->quality ? : default_quality; @@ -108,12 +189,6 @@ static inline int hwrng_init(struct hwrng *rng) return 0; } -static inline void hwrng_cleanup(struct hwrng *rng) -{ - if (rng && rng->cleanup) - rng->cleanup(rng); -} - static int rng_dev_open(struct inode *inode, struct file *filp) { /* enforce read-only access to this chrdev */ @@ -128,6 +203,7 @@ static inline int rng_get_data(struct hwrng *rng, u8 *buffer, size_t size, int wait) { int present; + BUG_ON(!mutex_is_locked(&reading_mutex)); if (rng->read) return rng->read(rng, (void *)buffer, size, wait); @@ -148,25 +224,27 @@ static ssize_t rng_dev_read(struct file *filp, char __user *buf, ssize_t ret = 0; int err = 0; int bytes_read, len; + struct hwrng *rng; while (size) { - if (mutex_lock_interruptible(&rng_mutex)) { - err = -ERESTARTSYS; + rng = get_current_rng(); + if (IS_ERR(rng)) { + err = PTR_ERR(rng); goto out; } - - if (!current_rng) { + if (!rng) { err = -ENODEV; - goto out_unlock; + goto out; } + mutex_lock(&reading_mutex); if (!data_avail) { - bytes_read = rng_get_data(current_rng, rng_buffer, + bytes_read = rng_get_data(rng, rng_buffer, rng_buffer_size(), !(filp->f_flags & O_NONBLOCK)); if (bytes_read < 0) { err = bytes_read; - goto out_unlock; + goto out_unlock_reading; } data_avail = bytes_read; } @@ -174,7 +252,7 @@ static ssize_t rng_dev_read(struct file *filp, char __user *buf, if (!data_avail) { if (filp->f_flags & O_NONBLOCK) { err = -EAGAIN; - goto out_unlock; + goto out_unlock_reading; } } else { len = data_avail; @@ -186,14 +264,15 @@ static ssize_t rng_dev_read(struct file *filp, char __user *buf, if (copy_to_user(buf + ret, rng_buffer + data_avail, len)) { err = -EFAULT; - goto out_unlock; + goto out_unlock_reading; } size -= len; ret += len; } - mutex_unlock(&rng_mutex); + mutex_unlock(&reading_mutex); + put_rng(rng); if (need_resched()) schedule_timeout_interruptible(1); @@ -205,8 +284,10 @@ static ssize_t rng_dev_read(struct file *filp, char __user *buf, } out: return ret ? : err; -out_unlock: - mutex_unlock(&rng_mutex); + +out_unlock_reading: + mutex_unlock(&reading_mutex); + put_rng(rng); goto out; } @@ -239,16 +320,9 @@ static ssize_t hwrng_attr_current_store(struct device *dev, err = -ENODEV; list_for_each_entry(rng, &rng_list, list) { if (strcmp(rng->name, buf) == 0) { - if (rng == current_rng) { - err = 0; - break; - } - err = hwrng_init(rng); - if (err) - break; - hwrng_cleanup(current_rng); - current_rng = rng; err = 0; + if (rng != current_rng) + err = set_current_rng(rng); break; } } @@ -261,17 +335,15 @@ static ssize_t hwrng_attr_current_show(struct device *dev, struct device_attribute *attr, char *buf) { - int err; ssize_t ret; - const char *name = "none"; + struct hwrng *rng; - err = mutex_lock_interruptible(&rng_mutex); - if (err) - return -ERESTARTSYS; - if (current_rng) - name = current_rng->name; - ret = snprintf(buf, PAGE_SIZE, "%s\n", name); - mutex_unlock(&rng_mutex); + rng = get_current_rng(); + if (IS_ERR(rng)) + return PTR_ERR(rng); + + ret = snprintf(buf, PAGE_SIZE, "%s\n", rng ? rng->name : "none"); + put_rng(rng); return ret; } @@ -305,14 +377,14 @@ static DEVICE_ATTR(rng_available, S_IRUGO, NULL); -static void unregister_miscdev(void) +static void __exit unregister_miscdev(void) { device_remove_file(rng_miscdev.this_device, &dev_attr_rng_available); device_remove_file(rng_miscdev.this_device, &dev_attr_rng_current); misc_deregister(&rng_miscdev); } -static int register_miscdev(void) +static int __init register_miscdev(void) { int err; @@ -342,15 +414,22 @@ static int hwrng_fillfn(void *unused) long rc; while (!kthread_should_stop()) { - if (!current_rng) + struct hwrng *rng; + + rng = get_current_rng(); + if (IS_ERR(rng) || !rng) break; - rc = rng_get_data(current_rng, rng_fillbuf, + mutex_lock(&reading_mutex); + rc = rng_get_data(rng, rng_fillbuf, rng_buffer_size(), 1); + mutex_unlock(&reading_mutex); + put_rng(rng); if (rc <= 0) { pr_warn("hwrng: no data available\n"); msleep_interruptible(10000); continue; } + /* Outside lock, sure, but y'know: randomness. */ add_hwgenerator_randomness((void *)rng_fillbuf, rc, rc * current_quality * 8 >> 10); } @@ -400,23 +479,16 @@ int hwrng_register(struct hwrng *rng) goto out_unlock; } + init_completion(&rng->cleanup_done); + complete(&rng->cleanup_done); + old_rng = current_rng; - if (!old_rng) { - err = hwrng_init(rng); - if (err) - goto out_unlock; - current_rng = rng; - } err = 0; if (!old_rng) { - err = register_miscdev(); - if (err) { - hwrng_cleanup(rng); - current_rng = NULL; + err = set_current_rng(rng); + if (err) goto out_unlock; - } } - INIT_LIST_HEAD(&rng->list); list_add_tail(&rng->list, &rng_list); if (old_rng && !rng->init) { @@ -439,42 +511,49 @@ EXPORT_SYMBOL_GPL(hwrng_register); void hwrng_unregister(struct hwrng *rng) { - int err; - mutex_lock(&rng_mutex); list_del(&rng->list); if (current_rng == rng) { - hwrng_cleanup(rng); - if (list_empty(&rng_list)) { - current_rng = NULL; - } else { - current_rng = list_entry(rng_list.prev, struct hwrng, list); - err = hwrng_init(current_rng); - if (err) - current_rng = NULL; + drop_current_rng(); + if (!list_empty(&rng_list)) { + struct hwrng *tail; + + tail = list_entry(rng_list.prev, struct hwrng, list); + + set_current_rng(tail); } } + if (list_empty(&rng_list)) { - unregister_miscdev(); + mutex_unlock(&rng_mutex); if (hwrng_fill) kthread_stop(hwrng_fill); - } + } else + mutex_unlock(&rng_mutex); - mutex_unlock(&rng_mutex); + wait_for_completion(&rng->cleanup_done); } EXPORT_SYMBOL_GPL(hwrng_unregister); -static void __exit hwrng_exit(void) +static int __init hwrng_modinit(void) +{ + return register_miscdev(); +} + +static void __exit hwrng_modexit(void) { mutex_lock(&rng_mutex); BUG_ON(current_rng); kfree(rng_buffer); kfree(rng_fillbuf); mutex_unlock(&rng_mutex); + + unregister_miscdev(); } -module_exit(hwrng_exit); +module_init(hwrng_modinit); +module_exit(hwrng_modexit); MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c index 72295ea2fd1c..3fa2f8a009b3 100644 --- a/drivers/char/hw_random/virtio-rng.c +++ b/drivers/char/hw_random/virtio-rng.c @@ -39,7 +39,6 @@ struct virtrng_info { bool hwrng_removed; }; - static void random_recv_done(struct virtqueue *vq) { struct virtrng_info *vi = vq->vdev->priv; diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c index e34a019eb930..24cc4ed9a780 100644 --- a/drivers/char/i8k.c +++ b/drivers/char/i8k.c @@ -5,7 +5,8 @@ * * Hwmon integration: * Copyright (C) 2011 Jean Delvare <jdelvare@suse.de> - * Copyright (C) 2013 Guenter Roeck <linux@roeck-us.net> + * Copyright (C) 2013, 2014 Guenter Roeck <linux@roeck-us.net> + * Copyright (C) 2014 Pali Rohár <pali.rohar@gmail.com> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -20,6 +21,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/delay.h> #include <linux/module.h> #include <linux/types.h> #include <linux/init.h> @@ -41,11 +43,15 @@ #define I8K_SMM_SET_FAN 0x01a3 #define I8K_SMM_GET_FAN 0x00a3 #define I8K_SMM_GET_SPEED 0x02a3 +#define I8K_SMM_GET_FAN_TYPE 0x03a3 +#define I8K_SMM_GET_NOM_SPEED 0x04a3 #define I8K_SMM_GET_TEMP 0x10a3 +#define I8K_SMM_GET_TEMP_TYPE 0x11a3 #define I8K_SMM_GET_DELL_SIG1 0xfea3 #define I8K_SMM_GET_DELL_SIG2 0xffa3 #define I8K_FAN_MULT 30 +#define I8K_FAN_MAX_RPM 30000 #define I8K_MAX_TEMP 127 #define I8K_FN_NONE 0x00 @@ -58,15 +64,13 @@ #define I8K_POWER_AC 0x05 #define I8K_POWER_BATTERY 0x01 -#define I8K_TEMPERATURE_BUG 1 - static DEFINE_MUTEX(i8k_mutex); static char bios_version[4]; static struct device *i8k_hwmon_dev; static u32 i8k_hwmon_flags; -static int i8k_fan_mult; -static int i8k_pwm_mult; -static int i8k_fan_max = I8K_FAN_HIGH; +static uint i8k_fan_mult = I8K_FAN_MULT; +static uint i8k_pwm_mult; +static uint i8k_fan_max = I8K_FAN_HIGH; #define I8K_HWMON_HAVE_TEMP1 (1 << 0) #define I8K_HWMON_HAVE_TEMP2 (1 << 1) @@ -95,13 +99,13 @@ static bool power_status; module_param(power_status, bool, 0600); MODULE_PARM_DESC(power_status, "Report power status in /proc/i8k"); -static int fan_mult = I8K_FAN_MULT; -module_param(fan_mult, int, 0); -MODULE_PARM_DESC(fan_mult, "Factor to multiply fan speed with"); +static uint fan_mult; +module_param(fan_mult, uint, 0); +MODULE_PARM_DESC(fan_mult, "Factor to multiply fan speed with (default: autodetect)"); -static int fan_max = I8K_FAN_HIGH; -module_param(fan_max, int, 0); -MODULE_PARM_DESC(fan_max, "Maximum configurable fan speed"); +static uint fan_max; +module_param(fan_max, uint, 0); +MODULE_PARM_DESC(fan_max, "Maximum configurable fan speed (default: autodetect)"); static int i8k_open_fs(struct inode *inode, struct file *file); static long i8k_ioctl(struct file *, unsigned int, unsigned long); @@ -276,6 +280,28 @@ static int i8k_get_fan_speed(int fan) } /* + * Read the fan type. + */ +static int i8k_get_fan_type(int fan) +{ + struct smm_regs regs = { .eax = I8K_SMM_GET_FAN_TYPE, }; + + regs.ebx = fan & 0xff; + return i8k_smm(®s) ? : regs.eax & 0xff; +} + +/* + * Read the fan nominal rpm for specific fan speed. + */ +static int i8k_get_fan_nominal_speed(int fan, int speed) +{ + struct smm_regs regs = { .eax = I8K_SMM_GET_NOM_SPEED, }; + + regs.ebx = (fan & 0xff) | (speed << 8); + return i8k_smm(®s) ? : (regs.eax & 0xffff) * i8k_fan_mult; +} + +/* * Set the fan speed (off, low, high). Returns the new fan status. */ static int i8k_set_fan(int fan, int speed) @@ -288,42 +314,52 @@ static int i8k_set_fan(int fan, int speed) return i8k_smm(®s) ? : i8k_get_fan_status(fan); } +static int i8k_get_temp_type(int sensor) +{ + struct smm_regs regs = { .eax = I8K_SMM_GET_TEMP_TYPE, }; + + regs.ebx = sensor & 0xff; + return i8k_smm(®s) ? : regs.eax & 0xff; +} + /* * Read the cpu temperature. */ -static int i8k_get_temp(int sensor) +static int _i8k_get_temp(int sensor) { - struct smm_regs regs = { .eax = I8K_SMM_GET_TEMP, }; - int rc; - int temp; + struct smm_regs regs = { + .eax = I8K_SMM_GET_TEMP, + .ebx = sensor & 0xff, + }; -#ifdef I8K_TEMPERATURE_BUG - static int prev[4] = { I8K_MAX_TEMP+1, I8K_MAX_TEMP+1, I8K_MAX_TEMP+1, I8K_MAX_TEMP+1 }; -#endif - regs.ebx = sensor & 0xff; - rc = i8k_smm(®s); - if (rc < 0) - return rc; + return i8k_smm(®s) ? : regs.eax & 0xff; +} - temp = regs.eax & 0xff; +static int i8k_get_temp(int sensor) +{ + int temp = _i8k_get_temp(sensor); -#ifdef I8K_TEMPERATURE_BUG /* * Sometimes the temperature sensor returns 0x99, which is out of range. - * In this case we return (once) the previous cached value. For example: + * In this case we retry (once) before returning an error. # 1003655137 00000058 00005a4b # 1003655138 00000099 00003a80 <--- 0x99 = 153 degrees # 1003655139 00000054 00005c52 */ - if (temp > I8K_MAX_TEMP) { - temp = prev[sensor]; - prev[sensor] = I8K_MAX_TEMP+1; - } else { - prev[sensor] = temp; + if (temp == 0x99) { + msleep(100); + temp = _i8k_get_temp(sensor); } + /* + * Return -ENODATA for all invalid temperatures. + * + * Known instances are the 0x99 value as seen above as well as + * 0xc1 (193), which may be returned when trying to read the GPU + * temperature if the system supports a GPU and it is currently + * turned off. + */ if (temp > I8K_MAX_TEMP) - return -ERANGE; -#endif + return -ENODATA; return temp; } @@ -493,6 +529,29 @@ static int i8k_open_fs(struct inode *inode, struct file *file) * Hwmon interface */ +static ssize_t i8k_hwmon_show_temp_label(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + static const char * const labels[] = { + "CPU", + "GPU", + "SODIMM", + "Other", + "Ambient", + "Other", + }; + int index = to_sensor_dev_attr(devattr)->index; + int type; + + type = i8k_get_temp_type(index); + if (type < 0) + return type; + if (type >= ARRAY_SIZE(labels)) + type = ARRAY_SIZE(labels) - 1; + return sprintf(buf, "%s\n", labels[type]); +} + static ssize_t i8k_hwmon_show_temp(struct device *dev, struct device_attribute *devattr, char *buf) @@ -501,13 +560,42 @@ static ssize_t i8k_hwmon_show_temp(struct device *dev, int temp; temp = i8k_get_temp(index); - if (temp == -ERANGE) - return -EINVAL; if (temp < 0) return temp; return sprintf(buf, "%d\n", temp * 1000); } +static ssize_t i8k_hwmon_show_fan_label(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + static const char * const labels[] = { + "Processor Fan", + "Motherboard Fan", + "Video Fan", + "Power Supply Fan", + "Chipset Fan", + "Other Fan", + }; + int index = to_sensor_dev_attr(devattr)->index; + bool dock = false; + int type; + + type = i8k_get_fan_type(index); + if (type < 0) + return type; + + if (type & 0x10) { + dock = true; + type &= 0x0F; + } + + if (type >= ARRAY_SIZE(labels)) + type = (ARRAY_SIZE(labels) - 1); + + return sprintf(buf, "%s%s\n", (dock ? "Docking " : ""), labels[type]); +} + static ssize_t i8k_hwmon_show_fan(struct device *dev, struct device_attribute *devattr, char *buf) @@ -555,45 +643,66 @@ static ssize_t i8k_hwmon_set_pwm(struct device *dev, } static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 0); +static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL, + 0); static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 1); +static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL, + 1); static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 2); +static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL, + 2); static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 3); -static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, i8k_hwmon_show_fan, NULL, - I8K_FAN_LEFT); +static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL, + 3); +static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, i8k_hwmon_show_fan, NULL, 0); +static SENSOR_DEVICE_ATTR(fan1_label, S_IRUGO, i8k_hwmon_show_fan_label, NULL, + 0); static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm, - i8k_hwmon_set_pwm, I8K_FAN_LEFT); + i8k_hwmon_set_pwm, 0); static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, i8k_hwmon_show_fan, NULL, - I8K_FAN_RIGHT); + 1); +static SENSOR_DEVICE_ATTR(fan2_label, S_IRUGO, i8k_hwmon_show_fan_label, NULL, + 1); static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm, - i8k_hwmon_set_pwm, I8K_FAN_RIGHT); + i8k_hwmon_set_pwm, 1); static struct attribute *i8k_attrs[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, /* 0 */ - &sensor_dev_attr_temp2_input.dev_attr.attr, /* 1 */ - &sensor_dev_attr_temp3_input.dev_attr.attr, /* 2 */ - &sensor_dev_attr_temp4_input.dev_attr.attr, /* 3 */ - &sensor_dev_attr_fan1_input.dev_attr.attr, /* 4 */ - &sensor_dev_attr_pwm1.dev_attr.attr, /* 5 */ - &sensor_dev_attr_fan2_input.dev_attr.attr, /* 6 */ - &sensor_dev_attr_pwm2.dev_attr.attr, /* 7 */ + &sensor_dev_attr_temp1_label.dev_attr.attr, /* 1 */ + &sensor_dev_attr_temp2_input.dev_attr.attr, /* 2 */ + &sensor_dev_attr_temp2_label.dev_attr.attr, /* 3 */ + &sensor_dev_attr_temp3_input.dev_attr.attr, /* 4 */ + &sensor_dev_attr_temp3_label.dev_attr.attr, /* 5 */ + &sensor_dev_attr_temp4_input.dev_attr.attr, /* 6 */ + &sensor_dev_attr_temp4_label.dev_attr.attr, /* 7 */ + &sensor_dev_attr_fan1_input.dev_attr.attr, /* 8 */ + &sensor_dev_attr_fan1_label.dev_attr.attr, /* 9 */ + &sensor_dev_attr_pwm1.dev_attr.attr, /* 10 */ + &sensor_dev_attr_fan2_input.dev_attr.attr, /* 11 */ + &sensor_dev_attr_fan2_label.dev_attr.attr, /* 12 */ + &sensor_dev_attr_pwm2.dev_attr.attr, /* 13 */ NULL }; static umode_t i8k_is_visible(struct kobject *kobj, struct attribute *attr, int index) { - if (index == 0 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP1)) + if (index >= 0 && index <= 1 && + !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP1)) return 0; - if (index == 1 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP2)) + if (index >= 2 && index <= 3 && + !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP2)) return 0; - if (index == 2 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP3)) + if (index >= 4 && index <= 5 && + !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP3)) return 0; - if (index == 3 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP4)) + if (index >= 6 && index <= 7 && + !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP4)) return 0; - if (index >= 4 && index <= 5 && + if (index >= 8 && index <= 10 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN1)) return 0; - if (index >= 6 && index <= 7 && + if (index >= 11 && index <= 13 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN2)) return 0; @@ -612,28 +721,28 @@ static int __init i8k_init_hwmon(void) i8k_hwmon_flags = 0; - /* CPU temperature attributes, if temperature reading is OK */ - err = i8k_get_temp(0); - if (err >= 0 || err == -ERANGE) + /* CPU temperature attributes, if temperature type is OK */ + err = i8k_get_temp_type(0); + if (err >= 0) i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP1; /* check for additional temperature sensors */ - err = i8k_get_temp(1); - if (err >= 0 || err == -ERANGE) + err = i8k_get_temp_type(1); + if (err >= 0) i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP2; - err = i8k_get_temp(2); - if (err >= 0 || err == -ERANGE) + err = i8k_get_temp_type(2); + if (err >= 0) i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP3; - err = i8k_get_temp(3); - if (err >= 0 || err == -ERANGE) + err = i8k_get_temp_type(3); + if (err >= 0) i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP4; - /* Left fan attributes, if left fan is present */ - err = i8k_get_fan_status(I8K_FAN_LEFT); + /* First fan attributes, if fan type is OK */ + err = i8k_get_fan_type(0); if (err >= 0) i8k_hwmon_flags |= I8K_HWMON_HAVE_FAN1; - /* Right fan attributes, if right fan is present */ - err = i8k_get_fan_status(I8K_FAN_RIGHT); + /* Second fan attributes, if fan type is OK */ + err = i8k_get_fan_type(1); if (err >= 0) i8k_hwmon_flags |= I8K_HWMON_HAVE_FAN2; @@ -649,16 +758,15 @@ static int __init i8k_init_hwmon(void) } struct i8k_config_data { - int fan_mult; - int fan_max; + uint fan_mult; + uint fan_max; }; enum i8k_configs { DELL_LATITUDE_D520, - DELL_LATITUDE_E6540, DELL_PRECISION_490, DELL_STUDIO, - DELL_XPS_M140, + DELL_XPS, }; static const struct i8k_config_data i8k_config_data[] = { @@ -666,10 +774,6 @@ static const struct i8k_config_data i8k_config_data[] = { .fan_mult = 1, .fan_max = I8K_FAN_TURBO, }, - [DELL_LATITUDE_E6540] = { - .fan_mult = 1, - .fan_max = I8K_FAN_HIGH, - }, [DELL_PRECISION_490] = { .fan_mult = 1, .fan_max = I8K_FAN_TURBO, @@ -678,7 +782,7 @@ static const struct i8k_config_data i8k_config_data[] = { .fan_mult = 1, .fan_max = I8K_FAN_HIGH, }, - [DELL_XPS_M140] = { + [DELL_XPS] = { .fan_mult = 1, .fan_max = I8K_FAN_HIGH, }, @@ -715,22 +819,6 @@ static struct dmi_system_id i8k_dmi_table[] __initdata = { .driver_data = (void *)&i8k_config_data[DELL_LATITUDE_D520], }, { - .ident = "Dell Latitude E6440", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6440"), - }, - .driver_data = (void *)&i8k_config_data[DELL_LATITUDE_E6540], - }, - { - .ident = "Dell Latitude E6540", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6540"), - }, - .driver_data = (void *)&i8k_config_data[DELL_LATITUDE_E6540], - }, - { .ident = "Dell Latitude 2", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), @@ -790,12 +878,20 @@ static struct dmi_system_id i8k_dmi_table[] __initdata = { .driver_data = (void *)&i8k_config_data[DELL_STUDIO], }, { + .ident = "Dell XPS 13", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "XPS13"), + }, + .driver_data = (void *)&i8k_config_data[DELL_XPS], + }, + { .ident = "Dell XPS M140", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_PRODUCT_NAME, "MXC051"), }, - .driver_data = (void *)&i8k_config_data[DELL_XPS_M140], + .driver_data = (void *)&i8k_config_data[DELL_XPS], }, { } }; @@ -808,6 +904,7 @@ MODULE_DEVICE_TABLE(dmi, i8k_dmi_table); static int __init i8k_probe(void) { const struct dmi_system_id *id; + int fan, ret; /* * Get DMI information @@ -836,19 +933,40 @@ static int __init i8k_probe(void) return -ENODEV; } - i8k_fan_mult = fan_mult; - i8k_fan_max = fan_max ? : I8K_FAN_HIGH; /* Must not be 0 */ + /* + * Set fan multiplier and maximal fan speed from dmi config + * Values specified in module parameters override values from dmi + */ id = dmi_first_match(i8k_dmi_table); if (id && id->driver_data) { const struct i8k_config_data *conf = id->driver_data; - - if (fan_mult == I8K_FAN_MULT && conf->fan_mult) - i8k_fan_mult = conf->fan_mult; - if (fan_max == I8K_FAN_HIGH && conf->fan_max) - i8k_fan_max = conf->fan_max; + if (!fan_mult && conf->fan_mult) + fan_mult = conf->fan_mult; + if (!fan_max && conf->fan_max) + fan_max = conf->fan_max; } + + i8k_fan_max = fan_max ? : I8K_FAN_HIGH; /* Must not be 0 */ i8k_pwm_mult = DIV_ROUND_UP(255, i8k_fan_max); + if (!fan_mult) { + /* + * Autodetect fan multiplier based on nominal rpm + * If fan reports rpm value too high then set multiplier to 1 + */ + for (fan = 0; fan < 2; ++fan) { + ret = i8k_get_fan_nominal_speed(fan, i8k_fan_max); + if (ret < 0) + continue; + if (ret > I8K_FAN_MAX_RPM) + i8k_fan_mult = 1; + break; + } + } else { + /* Fan multiplier was specified in module param or in dmi */ + i8k_fan_mult = fan_mult; + } + return 0; } diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 9a6b63783a94..297110c12635 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -28,7 +28,7 @@ #include <linux/io.h> #include <linux/aio.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> #ifdef CONFIG_IA64 # include <linux/efi.h> @@ -352,7 +352,6 @@ static int mmap_mem(struct file *file, struct vm_area_struct *vma) return 0; } -#ifdef CONFIG_DEVKMEM static int mmap_kmem(struct file *file, struct vm_area_struct *vma) { unsigned long pfn; @@ -373,9 +372,7 @@ static int mmap_kmem(struct file *file, struct vm_area_struct *vma) vma->vm_pgoff = pfn; return mmap_mem(file, vma); } -#endif -#ifdef CONFIG_DEVKMEM /* * This function reads the *virtual* memory as seen by the kernel. */ @@ -555,9 +552,7 @@ static ssize_t write_kmem(struct file *file, const char __user *buf, *ppos = p; return virtr + wrote ? : err; } -#endif -#ifdef CONFIG_DEVPORT static ssize_t read_port(struct file *file, char __user *buf, size_t count, loff_t *ppos) { @@ -586,6 +581,7 @@ static ssize_t write_port(struct file *file, const char __user *buf, return -EFAULT; while (count-- > 0 && i < 65536) { char c; + if (__get_user(c, tmp)) { if (tmp > buf) break; @@ -598,7 +594,6 @@ static ssize_t write_port(struct file *file, const char __user *buf, *ppos = i; return tmp-buf; } -#endif static ssize_t read_null(struct file *file, char __user *buf, size_t count, loff_t *ppos) @@ -642,6 +637,7 @@ static ssize_t read_iter_zero(struct kiocb *iocb, struct iov_iter *iter) while (iov_iter_count(iter)) { size_t chunk = iov_iter_count(iter), n; + if (chunk > PAGE_SIZE) chunk = PAGE_SIZE; /* Just for latency reasons */ n = iov_iter_zero(chunk, iter); @@ -726,7 +722,7 @@ static int open_port(struct inode *inode, struct file *filp) #define open_mem open_port #define open_kmem open_mem -static const struct file_operations mem_fops = { +static const struct file_operations __maybe_unused mem_fops = { .llseek = memory_lseek, .read = read_mem, .write = write_mem, @@ -738,8 +734,7 @@ static const struct file_operations mem_fops = { #endif }; -#ifdef CONFIG_DEVKMEM -static const struct file_operations kmem_fops = { +static const struct file_operations __maybe_unused kmem_fops = { .llseek = memory_lseek, .read = read_kmem, .write = write_kmem, @@ -750,7 +745,6 @@ static const struct file_operations kmem_fops = { .mmap_capabilities = memory_mmap_capabilities, #endif }; -#endif static const struct file_operations null_fops = { .llseek = null_lseek, @@ -761,14 +755,12 @@ static const struct file_operations null_fops = { .splice_write = splice_write_null, }; -#ifdef CONFIG_DEVPORT -static const struct file_operations port_fops = { +static const struct file_operations __maybe_unused port_fops = { .llseek = memory_lseek, .read = read_port, .write = write_port, .open = open_port, }; -#endif static const struct file_operations zero_fops = { .llseek = zero_lseek, @@ -795,7 +787,9 @@ static const struct memdev { const struct file_operations *fops; fmode_t fmode; } devlist[] = { +#ifdef CONFIG_DEVMEM [1] = { "mem", 0, &mem_fops, FMODE_UNSIGNED_OFFSET }, +#endif #ifdef CONFIG_DEVKMEM [2] = { "kmem", 0, &kmem_fops, FMODE_UNSIGNED_OFFSET }, #endif diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index bf53a3771da5..e85d3416d899 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -901,8 +901,10 @@ int tpm_pm_suspend(struct device *dev) if (chip == NULL) return -ENODEV; - if (chip->flags & TPM_CHIP_FLAG_TPM2) - return tpm2_shutdown(chip, TPM2_SU_CLEAR); + if (chip->flags & TPM_CHIP_FLAG_TPM2) { + tpm2_shutdown(chip, TPM2_SU_STATE); + return 0; + } /* for buggy tpm, flush pcrs with extend to selected dummy */ if (tpm_suspend_pcr) { diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 7b0727c5e803..f8319a0860fd 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -432,7 +432,8 @@ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value, const char *desc); extern int tpm2_startup(struct tpm_chip *chip, u16 startup_type); -extern int tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type); +extern void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type); extern unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *, u32); extern int tpm2_do_selftest(struct tpm_chip *chip); -extern int tpm2_gen_interrupt(struct tpm_chip *chip, bool quiet); +extern int tpm2_gen_interrupt(struct tpm_chip *chip); +extern int tpm2_probe(struct tpm_chip *chip); diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index 1abe6502219f..011909a9be96 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -456,20 +456,23 @@ static const struct tpm_input_header tpm2_shutdown_header = { * @chip: TPM chip to use. * @shutdown_type shutdown type. The value is either * TPM_SU_CLEAR or TPM_SU_STATE. - * - * 0 is returned when the operation is successful. If a negative number is - * returned it remarks a POSIX error code. If a positive number is returned - * it remarks a TPM error. */ -int tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type) +void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type) { struct tpm2_cmd cmd; + int rc; cmd.header.in = tpm2_shutdown_header; - cmd.params.startup_in.startup_type = cpu_to_be16(shutdown_type); - return tpm_transmit_cmd(chip, &cmd, sizeof(cmd), - "stopping the TPM"); + + rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), "stopping the TPM"); + + /* In places where shutdown command is sent there's no much we can do + * except print the error code on a system failure. + */ + if (rc < 0) + dev_warn(chip->pdev, "transmit returned %d while stopping the TPM", + rc); } EXPORT_SYMBOL_GPL(tpm2_shutdown); @@ -598,20 +601,46 @@ EXPORT_SYMBOL_GPL(tpm2_do_selftest); /** * tpm2_gen_interrupt() - generate an interrupt * @chip: TPM chip to use - * @quiet: surpress the error message * * 0 is returned when the operation is successful. If a negative number is * returned it remarks a POSIX error code. If a positive number is returned * it remarks a TPM error. */ -int tpm2_gen_interrupt(struct tpm_chip *chip, bool quiet) +int tpm2_gen_interrupt(struct tpm_chip *chip) { - const char *desc = NULL; u32 dummy; - if (!quiet) - desc = "attempting to generate an interrupt"; - - return tpm2_get_tpm_pt(chip, TPM2_CAP_TPM_PROPERTIES, &dummy, desc); + return tpm2_get_tpm_pt(chip, 0x100, &dummy, + "attempting to generate an interrupt"); } EXPORT_SYMBOL_GPL(tpm2_gen_interrupt); + +/** + * tpm2_probe() - probe TPM 2.0 + * @chip: TPM chip to use + * + * Send idempotent TPM 2.0 command and see whether TPM 2.0 chip replied based on + * the reply tag. + */ +int tpm2_probe(struct tpm_chip *chip) +{ + struct tpm2_cmd cmd; + int rc; + + cmd.header.in = tpm2_get_tpm_pt_header; + cmd.params.get_tpm_pt_in.cap_id = cpu_to_be32(TPM2_CAP_TPM_PROPERTIES); + cmd.params.get_tpm_pt_in.property_id = cpu_to_be32(0x100); + cmd.params.get_tpm_pt_in.property_cnt = cpu_to_be32(1); + + rc = tpm_transmit(chip, (const char *) &cmd, sizeof(cmd)); + if (rc < 0) + return rc; + else if (rc < TPM_HEADER_SIZE) + return -EFAULT; + + if (be16_to_cpu(cmd.header.out.tag) == TPM2_ST_NO_SESSIONS) + chip->flags |= TPM_CHIP_FLAG_TPM2; + + return 0; +} +EXPORT_SYMBOL_GPL(tpm2_probe); diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index 3dd23cfae4fe..b26ceee3585e 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -95,21 +95,7 @@ struct crb_priv { u8 __iomem *rsp; }; -#ifdef CONFIG_PM_SLEEP -static int crb_resume(struct device *dev) -{ - int rc; - struct tpm_chip *chip = dev_get_drvdata(dev); - - rc = tpm2_shutdown(chip, TPM2_SU_STATE); - if (!rc) - rc = tpm2_do_selftest(chip); - - return rc; -} -#endif - -static SIMPLE_DEV_PM_OPS(crb_pm, tpm_pm_suspend, crb_resume); +static SIMPLE_DEV_PM_OPS(crb_pm, tpm_pm_suspend, tpm_pm_resume); static u8 crb_status(struct tpm_chip *chip) { @@ -326,6 +312,10 @@ static int crb_acpi_remove(struct acpi_device *device) struct tpm_chip *chip = dev_get_drvdata(dev); tpm_chip_unregister(chip); + + if (chip->flags & TPM_CHIP_FLAG_TPM2) + tpm2_shutdown(chip, TPM2_SU_CLEAR); + return 0; } diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c index 0840347e251c..b1e53e3aece5 100644 --- a/drivers/char/tpm/tpm_ibmvtpm.c +++ b/drivers/char/tpm/tpm_ibmvtpm.c @@ -148,7 +148,8 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count) crq.len = (u16)count; crq.data = ibmvtpm->rtce_dma_handle; - rc = ibmvtpm_send_crq(ibmvtpm->vdev, word[0], word[1]); + rc = ibmvtpm_send_crq(ibmvtpm->vdev, cpu_to_be64(word[0]), + cpu_to_be64(word[1])); if (rc != H_SUCCESS) { dev_err(ibmvtpm->dev, "tpm_ibmvtpm_send failed rc=%d\n", rc); rc = 0; @@ -186,7 +187,8 @@ static int ibmvtpm_crq_get_rtce_size(struct ibmvtpm_dev *ibmvtpm) crq.valid = (u8)IBMVTPM_VALID_CMD; crq.msg = (u8)VTPM_GET_RTCE_BUFFER_SIZE; - rc = ibmvtpm_send_crq(ibmvtpm->vdev, buf[0], buf[1]); + rc = ibmvtpm_send_crq(ibmvtpm->vdev, cpu_to_be64(buf[0]), + cpu_to_be64(buf[1])); if (rc != H_SUCCESS) dev_err(ibmvtpm->dev, "ibmvtpm_crq_get_rtce_size failed rc=%d\n", rc); @@ -212,7 +214,8 @@ static int ibmvtpm_crq_get_version(struct ibmvtpm_dev *ibmvtpm) crq.valid = (u8)IBMVTPM_VALID_CMD; crq.msg = (u8)VTPM_GET_VERSION; - rc = ibmvtpm_send_crq(ibmvtpm->vdev, buf[0], buf[1]); + rc = ibmvtpm_send_crq(ibmvtpm->vdev, cpu_to_be64(buf[0]), + cpu_to_be64(buf[1])); if (rc != H_SUCCESS) dev_err(ibmvtpm->dev, "ibmvtpm_crq_get_version failed rc=%d\n", rc); @@ -336,7 +339,8 @@ static int tpm_ibmvtpm_suspend(struct device *dev) crq.valid = (u8)IBMVTPM_VALID_CMD; crq.msg = (u8)VTPM_PREPARE_TO_SUSPEND; - rc = ibmvtpm_send_crq(ibmvtpm->vdev, buf[0], buf[1]); + rc = ibmvtpm_send_crq(ibmvtpm->vdev, cpu_to_be64(buf[0]), + cpu_to_be64(buf[1])); if (rc != H_SUCCESS) dev_err(ibmvtpm->dev, "tpm_ibmvtpm_suspend failed rc=%d\n", rc); @@ -481,11 +485,11 @@ static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq, case IBMVTPM_VALID_CMD: switch (crq->msg) { case VTPM_GET_RTCE_BUFFER_SIZE_RES: - if (crq->len <= 0) { + if (be16_to_cpu(crq->len) <= 0) { dev_err(ibmvtpm->dev, "Invalid rtce size\n"); return; } - ibmvtpm->rtce_size = crq->len; + ibmvtpm->rtce_size = be16_to_cpu(crq->len); ibmvtpm->rtce_buf = kmalloc(ibmvtpm->rtce_size, GFP_KERNEL); if (!ibmvtpm->rtce_buf) { @@ -506,11 +510,11 @@ static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq, return; case VTPM_GET_VERSION_RES: - ibmvtpm->vtpm_version = crq->data; + ibmvtpm->vtpm_version = be32_to_cpu(crq->data); return; case VTPM_TPM_COMMAND_RES: /* len of the data in rtce buffer */ - ibmvtpm->res_len = crq->len; + ibmvtpm->res_len = be16_to_cpu(crq->len); wake_up_interruptible(&ibmvtpm->wq); return; default: diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 6725bef7cb96..f2dffa770b8e 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -588,6 +588,9 @@ MODULE_PARM_DESC(interrupts, "Enable interrupts"); static void tpm_tis_remove(struct tpm_chip *chip) { + if (chip->flags & TPM_CHIP_FLAG_TPM2) + tpm2_shutdown(chip, TPM2_SU_CLEAR); + iowrite32(~TPM_GLOBAL_INT_ENABLE & ioread32(chip->vendor.iobase + TPM_INT_ENABLE(chip->vendor. @@ -639,12 +642,9 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle, goto out_err; } - /* Every TPM 2.x command has a higher ordinal than TPM 1.x commands. - * Therefore, we can use an idempotent TPM 2.x command to probe TPM 2.x. - */ - rc = tpm2_gen_interrupt(chip, true); - if (rc == 0 || rc == TPM2_RC_INITIALIZE) - chip->flags |= TPM_CHIP_FLAG_TPM2; + rc = tpm2_probe(chip); + if (rc) + goto out_err; vendor = ioread32(chip->vendor.iobase + TPM_DID_VID(0)); chip->vendor.manufacturer_id = vendor; @@ -747,7 +747,7 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle, /* Generate Interrupts */ if (chip->flags & TPM_CHIP_FLAG_TPM2) - tpm2_gen_interrupt(chip, false); + tpm2_gen_interrupt(chip); else tpm_gen_interrupt(chip); @@ -865,25 +865,22 @@ static void tpm_tis_reenable_interrupts(struct tpm_chip *chip) static int tpm_tis_resume(struct device *dev) { struct tpm_chip *chip = dev_get_drvdata(dev); - int ret = 0; + int ret; if (chip->vendor.irq) tpm_tis_reenable_interrupts(chip); - if (chip->flags & TPM_CHIP_FLAG_TPM2) { - /* NOP if firmware properly does this. */ - tpm2_startup(chip, TPM2_SU_STATE); + ret = tpm_pm_resume(dev); + if (ret) + return ret; - ret = tpm2_shutdown(chip, TPM2_SU_STATE); - if (!ret) - ret = tpm2_do_selftest(chip); - } else { - ret = tpm_pm_resume(dev); - if (!ret) - tpm_do_selftest(chip); - } + /* TPM 1.2 requires self-test on resume. This function actually returns + * an error code but for unknown reason it isn't handled. + */ + if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) + tpm_do_selftest(chip); - return ret; + return 0; } #endif diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index de03df9dd7c9..26afb56a8073 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1986,6 +1986,12 @@ static int virtcons_probe(struct virtio_device *vdev) bool multiport; bool early = early_put_chars != NULL; + if (!vdev->config->get) { + dev_err(&vdev->dev, "%s failure: config access disabled\n", + __func__); + return -EINVAL; + } + /* Ensure to read early_put_chars now */ barrier(); |