diff options
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/Kconfig | 8 | ||||
-rw-r--r-- | drivers/char/Makefile | 2 | ||||
-rw-r--r-- | drivers/char/hw_random/bcm63xx-rng.c | 18 | ||||
-rw-r--r-- | drivers/char/hw_random/via-rng.c | 2 | ||||
-rw-r--r-- | drivers/char/i8k.c | 1007 | ||||
-rw-r--r-- | drivers/char/ipmi/ipmi_msghandler.c | 4 | ||||
-rw-r--r-- | drivers/char/ipmi/ipmi_powernv.c | 39 | ||||
-rw-r--r-- | drivers/char/ipmi/ipmi_si_intf.c | 16 | ||||
-rw-r--r-- | drivers/char/ipmi/ipmi_ssif.c | 213 | ||||
-rw-r--r-- | drivers/char/misc.c | 23 | ||||
-rw-r--r-- | drivers/char/msm_smd_pkt.c | 465 | ||||
-rw-r--r-- | drivers/char/pcmcia/cm4040_cs.c | 5 | ||||
-rw-r--r-- | drivers/char/pcmcia/synclink_cs.c | 2 | ||||
-rw-r--r-- | drivers/char/random.c | 80 | ||||
-rw-r--r-- | drivers/char/raw.c | 1 | ||||
-rw-r--r-- | drivers/char/snsc.c | 4 | ||||
-rw-r--r-- | drivers/char/virtio_console.c | 4 | ||||
-rw-r--r-- | drivers/char/xilinx_hwicap/buffer_icap.c | 6 | ||||
-rw-r--r-- | drivers/char/xillybus/Kconfig | 2 |
19 files changed, 326 insertions, 1575 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index a4af8221751e..a043107da2af 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -590,14 +590,6 @@ config DEVPORT source "drivers/s390/char/Kconfig" -config MSM_SMD_PKT - bool "Enable device interface for some SMD packet ports" - default n - depends on MSM_SMD - help - Enables userspace clients to read and write to some packet SMD - ports via device interface for MSM chipset. - config TILE_SROM bool "Character-device access via hypervisor to the Tilera SPI ROM" depends on TILE diff --git a/drivers/char/Makefile b/drivers/char/Makefile index d06cde26031b..d8a7579300d2 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -9,7 +9,6 @@ obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o obj-$(CONFIG_RAW_DRIVER) += raw.o obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o -obj-$(CONFIG_MSM_SMD_PKT) += msm_smd_pkt.o obj-$(CONFIG_MSPEC) += mspec.o obj-$(CONFIG_MMTIMER) += mmtimer.o obj-$(CONFIG_UV_MMTIMER) += uv_mmtimer.o @@ -36,7 +35,6 @@ else obj-$(CONFIG_NVRAM) += nvram.o endif obj-$(CONFIG_TOSHIBA) += toshiba.o -obj-$(CONFIG_I8K) += i8k.o obj-$(CONFIG_DS1620) += ds1620.o obj-$(CONFIG_HW_RANDOM) += hw_random/ obj-$(CONFIG_PPDEV) += ppdev.o diff --git a/drivers/char/hw_random/bcm63xx-rng.c b/drivers/char/hw_random/bcm63xx-rng.c index d1494ecd9e11..4b31f1387f37 100644 --- a/drivers/char/hw_random/bcm63xx-rng.c +++ b/drivers/char/hw_random/bcm63xx-rng.c @@ -57,7 +57,7 @@ static void bcm63xx_rng_cleanup(struct hwrng *rng) val &= ~RNG_EN; __raw_writel(val, priv->regs + RNG_CTRL); - clk_didsable_unprepare(prov->clk); + clk_disable_unprepare(priv->clk); } static int bcm63xx_rng_data_present(struct hwrng *rng, int wait) @@ -97,14 +97,14 @@ static int bcm63xx_rng_probe(struct platform_device *pdev) priv->rng.name = pdev->name; priv->rng.init = bcm63xx_rng_init; priv->rng.cleanup = bcm63xx_rng_cleanup; - prov->rng.data_present = bcm63xx_rng_data_present; + priv->rng.data_present = bcm63xx_rng_data_present; priv->rng.data_read = bcm63xx_rng_data_read; priv->clk = devm_clk_get(&pdev->dev, "ipsec"); if (IS_ERR(priv->clk)) { - error = PTR_ERR(priv->clk); - dev_err(&pdev->dev, "no clock for device: %d\n", error); - return error; + ret = PTR_ERR(priv->clk); + dev_err(&pdev->dev, "no clock for device: %d\n", ret); + return ret; } if (!devm_request_mem_region(&pdev->dev, r->start, @@ -120,11 +120,11 @@ static int bcm63xx_rng_probe(struct platform_device *pdev) return -ENOMEM; } - error = devm_hwrng_register(&pdev->dev, &priv->rng); - if (error) { + ret = devm_hwrng_register(&pdev->dev, &priv->rng); + if (ret) { dev_err(&pdev->dev, "failed to register rng device: %d\n", - error); - return error; + ret); + return ret; } dev_info(&pdev->dev, "registered RNG driver\n"); diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c index a3bebef255ad..0c98a9d51a24 100644 --- a/drivers/char/hw_random/via-rng.c +++ b/drivers/char/hw_random/via-rng.c @@ -33,7 +33,7 @@ #include <asm/io.h> #include <asm/msr.h> #include <asm/cpufeature.h> -#include <asm/i387.h> +#include <asm/fpu/api.h> diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c deleted file mode 100644 index a43048b5b05f..000000000000 --- a/drivers/char/i8k.c +++ /dev/null @@ -1,1007 +0,0 @@ -/* - * i8k.c -- Linux driver for accessing the SMM BIOS on Dell laptops. - * - * Copyright (C) 2001 Massimo Dal Zotto <dz@debian.org> - * - * Hwmon integration: - * Copyright (C) 2011 Jean Delvare <jdelvare@suse.de> - * 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 - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/delay.h> -#include <linux/module.h> -#include <linux/types.h> -#include <linux/init.h> -#include <linux/proc_fs.h> -#include <linux/seq_file.h> -#include <linux/dmi.h> -#include <linux/capability.h> -#include <linux/mutex.h> -#include <linux/hwmon.h> -#include <linux/hwmon-sysfs.h> -#include <linux/uaccess.h> -#include <linux/io.h> -#include <linux/sched.h> - -#include <linux/i8k.h> - -#define I8K_SMM_FN_STATUS 0x0025 -#define I8K_SMM_POWER_STATUS 0x0069 -#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 -#define I8K_FN_UP 0x01 -#define I8K_FN_DOWN 0x02 -#define I8K_FN_MUTE 0x04 -#define I8K_FN_MASK 0x07 -#define I8K_FN_SHIFT 8 - -#define I8K_POWER_AC 0x05 -#define I8K_POWER_BATTERY 0x01 - -static DEFINE_MUTEX(i8k_mutex); -static char bios_version[4]; -static struct device *i8k_hwmon_dev; -static u32 i8k_hwmon_flags; -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) -#define I8K_HWMON_HAVE_TEMP3 (1 << 2) -#define I8K_HWMON_HAVE_TEMP4 (1 << 3) -#define I8K_HWMON_HAVE_FAN1 (1 << 4) -#define I8K_HWMON_HAVE_FAN2 (1 << 5) - -MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)"); -MODULE_DESCRIPTION("Driver for accessing SMM BIOS on Dell laptops"); -MODULE_LICENSE("GPL"); - -static bool force; -module_param(force, bool, 0); -MODULE_PARM_DESC(force, "Force loading without checking for supported models"); - -static bool ignore_dmi; -module_param(ignore_dmi, bool, 0); -MODULE_PARM_DESC(ignore_dmi, "Continue probing hardware even if DMI data does not match"); - -static bool restricted; -module_param(restricted, bool, 0); -MODULE_PARM_DESC(restricted, "Allow fan control if SYS_ADMIN capability set"); - -static bool power_status; -module_param(power_status, bool, 0600); -MODULE_PARM_DESC(power_status, "Report power status in /proc/i8k"); - -static uint fan_mult; -module_param(fan_mult, uint, 0); -MODULE_PARM_DESC(fan_mult, "Factor to multiply fan speed with (default: autodetect)"); - -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); - -static const struct file_operations i8k_fops = { - .owner = THIS_MODULE, - .open = i8k_open_fs, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .unlocked_ioctl = i8k_ioctl, -}; - -struct smm_regs { - unsigned int eax; - unsigned int ebx __packed; - unsigned int ecx __packed; - unsigned int edx __packed; - unsigned int esi __packed; - unsigned int edi __packed; -}; - -static inline const char *i8k_get_dmi_data(int field) -{ - const char *dmi_data = dmi_get_system_info(field); - - return dmi_data && *dmi_data ? dmi_data : "?"; -} - -/* - * Call the System Management Mode BIOS. Code provided by Jonathan Buzzard. - */ -static int i8k_smm(struct smm_regs *regs) -{ - int rc; - int eax = regs->eax; - cpumask_var_t old_mask; - - /* SMM requires CPU 0 */ - if (!alloc_cpumask_var(&old_mask, GFP_KERNEL)) - return -ENOMEM; - cpumask_copy(old_mask, ¤t->cpus_allowed); - rc = set_cpus_allowed_ptr(current, cpumask_of(0)); - if (rc) - goto out; - if (smp_processor_id() != 0) { - rc = -EBUSY; - goto out; - } - -#if defined(CONFIG_X86_64) - asm volatile("pushq %%rax\n\t" - "movl 0(%%rax),%%edx\n\t" - "pushq %%rdx\n\t" - "movl 4(%%rax),%%ebx\n\t" - "movl 8(%%rax),%%ecx\n\t" - "movl 12(%%rax),%%edx\n\t" - "movl 16(%%rax),%%esi\n\t" - "movl 20(%%rax),%%edi\n\t" - "popq %%rax\n\t" - "out %%al,$0xb2\n\t" - "out %%al,$0x84\n\t" - "xchgq %%rax,(%%rsp)\n\t" - "movl %%ebx,4(%%rax)\n\t" - "movl %%ecx,8(%%rax)\n\t" - "movl %%edx,12(%%rax)\n\t" - "movl %%esi,16(%%rax)\n\t" - "movl %%edi,20(%%rax)\n\t" - "popq %%rdx\n\t" - "movl %%edx,0(%%rax)\n\t" - "pushfq\n\t" - "popq %%rax\n\t" - "andl $1,%%eax\n" - : "=a"(rc) - : "a"(regs) - : "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory"); -#else - asm volatile("pushl %%eax\n\t" - "movl 0(%%eax),%%edx\n\t" - "push %%edx\n\t" - "movl 4(%%eax),%%ebx\n\t" - "movl 8(%%eax),%%ecx\n\t" - "movl 12(%%eax),%%edx\n\t" - "movl 16(%%eax),%%esi\n\t" - "movl 20(%%eax),%%edi\n\t" - "popl %%eax\n\t" - "out %%al,$0xb2\n\t" - "out %%al,$0x84\n\t" - "xchgl %%eax,(%%esp)\n\t" - "movl %%ebx,4(%%eax)\n\t" - "movl %%ecx,8(%%eax)\n\t" - "movl %%edx,12(%%eax)\n\t" - "movl %%esi,16(%%eax)\n\t" - "movl %%edi,20(%%eax)\n\t" - "popl %%edx\n\t" - "movl %%edx,0(%%eax)\n\t" - "lahf\n\t" - "shrl $8,%%eax\n\t" - "andl $1,%%eax\n" - : "=a"(rc) - : "a"(regs) - : "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory"); -#endif - if (rc != 0 || (regs->eax & 0xffff) == 0xffff || regs->eax == eax) - rc = -EINVAL; - -out: - set_cpus_allowed_ptr(current, old_mask); - free_cpumask_var(old_mask); - return rc; -} - -/* - * Read the Fn key status. - */ -static int i8k_get_fn_status(void) -{ - struct smm_regs regs = { .eax = I8K_SMM_FN_STATUS, }; - int rc; - - rc = i8k_smm(®s); - if (rc < 0) - return rc; - - switch ((regs.eax >> I8K_FN_SHIFT) & I8K_FN_MASK) { - case I8K_FN_UP: - return I8K_VOL_UP; - case I8K_FN_DOWN: - return I8K_VOL_DOWN; - case I8K_FN_MUTE: - return I8K_VOL_MUTE; - default: - return 0; - } -} - -/* - * Read the power status. - */ -static int i8k_get_power_status(void) -{ - struct smm_regs regs = { .eax = I8K_SMM_POWER_STATUS, }; - int rc; - - rc = i8k_smm(®s); - if (rc < 0) - return rc; - - return (regs.eax & 0xff) == I8K_POWER_AC ? I8K_AC : I8K_BATTERY; -} - -/* - * Read the fan status. - */ -static int i8k_get_fan_status(int fan) -{ - struct smm_regs regs = { .eax = I8K_SMM_GET_FAN, }; - - regs.ebx = fan & 0xff; - return i8k_smm(®s) ? : regs.eax & 0xff; -} - -/* - * Read the fan speed in RPM. - */ -static int i8k_get_fan_speed(int fan) -{ - struct smm_regs regs = { .eax = I8K_SMM_GET_SPEED, }; - - regs.ebx = fan & 0xff; - return i8k_smm(®s) ? : (regs.eax & 0xffff) * i8k_fan_mult; -} - -/* - * 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) -{ - struct smm_regs regs = { .eax = I8K_SMM_SET_FAN, }; - - speed = (speed < 0) ? 0 : ((speed > i8k_fan_max) ? i8k_fan_max : speed); - regs.ebx = (fan & 0xff) | (speed << 8); - - 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) -{ - struct smm_regs regs = { - .eax = I8K_SMM_GET_TEMP, - .ebx = sensor & 0xff, - }; - - return i8k_smm(®s) ? : regs.eax & 0xff; -} - -static int i8k_get_temp(int sensor) -{ - int temp = _i8k_get_temp(sensor); - - /* - * Sometimes the temperature sensor returns 0x99, which is out of range. - * In this case we retry (once) before returning an error. - # 1003655137 00000058 00005a4b - # 1003655138 00000099 00003a80 <--- 0x99 = 153 degrees - # 1003655139 00000054 00005c52 - */ - 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 -ENODATA; - - return temp; -} - -static int i8k_get_dell_signature(int req_fn) -{ - struct smm_regs regs = { .eax = req_fn, }; - int rc; - - rc = i8k_smm(®s); - if (rc < 0) - return rc; - - return regs.eax == 1145651527 && regs.edx == 1145392204 ? 0 : -1; -} - -static int -i8k_ioctl_unlocked(struct file *fp, unsigned int cmd, unsigned long arg) -{ - int val = 0; - int speed; - unsigned char buff[16]; - int __user *argp = (int __user *)arg; - - if (!argp) - return -EINVAL; - - switch (cmd) { - case I8K_BIOS_VERSION: - val = (bios_version[0] << 16) | - (bios_version[1] << 8) | bios_version[2]; - break; - - case I8K_MACHINE_ID: - memset(buff, 0, 16); - strlcpy(buff, i8k_get_dmi_data(DMI_PRODUCT_SERIAL), - sizeof(buff)); - break; - - case I8K_FN_STATUS: - val = i8k_get_fn_status(); - break; - - case I8K_POWER_STATUS: - val = i8k_get_power_status(); - break; - - case I8K_GET_TEMP: - val = i8k_get_temp(0); - break; - - case I8K_GET_SPEED: - if (copy_from_user(&val, argp, sizeof(int))) - return -EFAULT; - - val = i8k_get_fan_speed(val); - break; - - case I8K_GET_FAN: - if (copy_from_user(&val, argp, sizeof(int))) - return -EFAULT; - - val = i8k_get_fan_status(val); - break; - - case I8K_SET_FAN: - if (restricted && !capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (copy_from_user(&val, argp, sizeof(int))) - return -EFAULT; - - if (copy_from_user(&speed, argp + 1, sizeof(int))) - return -EFAULT; - - val = i8k_set_fan(val, speed); - break; - - default: - return -EINVAL; - } - - if (val < 0) - return val; - - switch (cmd) { - case I8K_BIOS_VERSION: - if (copy_to_user(argp, &val, 4)) - return -EFAULT; - - break; - case I8K_MACHINE_ID: - if (copy_to_user(argp, buff, 16)) - return -EFAULT; - - break; - default: - if (copy_to_user(argp, &val, sizeof(int))) - return -EFAULT; - - break; - } - - return 0; -} - -static long i8k_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) -{ - long ret; - - mutex_lock(&i8k_mutex); - ret = i8k_ioctl_unlocked(fp, cmd, arg); - mutex_unlock(&i8k_mutex); - - return ret; -} - -/* - * Print the information for /proc/i8k. - */ -static int i8k_proc_show(struct seq_file *seq, void *offset) -{ - int fn_key, cpu_temp, ac_power; - int left_fan, right_fan, left_speed, right_speed; - - cpu_temp = i8k_get_temp(0); /* 11100 µs */ - left_fan = i8k_get_fan_status(I8K_FAN_LEFT); /* 580 µs */ - right_fan = i8k_get_fan_status(I8K_FAN_RIGHT); /* 580 µs */ - left_speed = i8k_get_fan_speed(I8K_FAN_LEFT); /* 580 µs */ - right_speed = i8k_get_fan_speed(I8K_FAN_RIGHT); /* 580 µs */ - fn_key = i8k_get_fn_status(); /* 750 µs */ - if (power_status) - ac_power = i8k_get_power_status(); /* 14700 µs */ - else - ac_power = -1; - - /* - * Info: - * - * 1) Format version (this will change if format changes) - * 2) BIOS version - * 3) BIOS machine ID - * 4) Cpu temperature - * 5) Left fan status - * 6) Right fan status - * 7) Left fan speed - * 8) Right fan speed - * 9) AC power - * 10) Fn Key status - */ - seq_printf(seq, "%s %s %s %d %d %d %d %d %d %d\n", - I8K_PROC_FMT, - bios_version, - i8k_get_dmi_data(DMI_PRODUCT_SERIAL), - cpu_temp, - left_fan, right_fan, left_speed, right_speed, - ac_power, fn_key); - - return 0; -} - -static int i8k_open_fs(struct inode *inode, struct file *file) -{ - return single_open(file, i8k_proc_show, NULL); -} - - -/* - * 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) -{ - int index = to_sensor_dev_attr(devattr)->index; - int temp; - - temp = i8k_get_temp(index); - 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) -{ - int index = to_sensor_dev_attr(devattr)->index; - int fan_speed; - - fan_speed = i8k_get_fan_speed(index); - if (fan_speed < 0) - return fan_speed; - return sprintf(buf, "%d\n", fan_speed); -} - -static ssize_t i8k_hwmon_show_pwm(struct device *dev, - struct device_attribute *devattr, - char *buf) -{ - int index = to_sensor_dev_attr(devattr)->index; - int status; - - status = i8k_get_fan_status(index); - if (status < 0) - return -EIO; - return sprintf(buf, "%d\n", clamp_val(status * i8k_pwm_mult, 0, 255)); -} - -static ssize_t i8k_hwmon_set_pwm(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - int index = to_sensor_dev_attr(attr)->index; - unsigned long val; - int err; - - err = kstrtoul(buf, 10, &val); - if (err) - return err; - val = clamp_val(DIV_ROUND_CLOSEST(val, i8k_pwm_mult), 0, i8k_fan_max); - - mutex_lock(&i8k_mutex); - err = i8k_set_fan(index, val); - mutex_unlock(&i8k_mutex); - - return err < 0 ? -EIO : count; -} - -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(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, 0); -static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, i8k_hwmon_show_fan, NULL, - 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, 1); - -static struct attribute *i8k_attrs[] = { - &sensor_dev_attr_temp1_input.dev_attr.attr, /* 0 */ - &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 && index <= 1 && - !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP1)) - return 0; - if (index >= 2 && index <= 3 && - !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP2)) - return 0; - if (index >= 4 && index <= 5 && - !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP3)) - return 0; - if (index >= 6 && index <= 7 && - !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP4)) - return 0; - if (index >= 8 && index <= 10 && - !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN1)) - return 0; - if (index >= 11 && index <= 13 && - !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN2)) - return 0; - - return attr->mode; -} - -static const struct attribute_group i8k_group = { - .attrs = i8k_attrs, - .is_visible = i8k_is_visible, -}; -__ATTRIBUTE_GROUPS(i8k); - -static int __init i8k_init_hwmon(void) -{ - int err; - - i8k_hwmon_flags = 0; - - /* 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_type(1); - if (err >= 0) - i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP2; - err = i8k_get_temp_type(2); - if (err >= 0) - i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP3; - err = i8k_get_temp_type(3); - if (err >= 0) - i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP4; - - /* First fan attributes, if fan type is OK */ - err = i8k_get_fan_type(0); - if (err >= 0) - i8k_hwmon_flags |= I8K_HWMON_HAVE_FAN1; - - /* Second fan attributes, if fan type is OK */ - err = i8k_get_fan_type(1); - if (err >= 0) - i8k_hwmon_flags |= I8K_HWMON_HAVE_FAN2; - - i8k_hwmon_dev = hwmon_device_register_with_groups(NULL, "i8k", NULL, - i8k_groups); - if (IS_ERR(i8k_hwmon_dev)) { - err = PTR_ERR(i8k_hwmon_dev); - i8k_hwmon_dev = NULL; - pr_err("hwmon registration failed (%d)\n", err); - return err; - } - return 0; -} - -struct i8k_config_data { - uint fan_mult; - uint fan_max; -}; - -enum i8k_configs { - DELL_LATITUDE_D520, - DELL_PRECISION_490, - DELL_STUDIO, - DELL_XPS, -}; - -static const struct i8k_config_data i8k_config_data[] = { - [DELL_LATITUDE_D520] = { - .fan_mult = 1, - .fan_max = I8K_FAN_TURBO, - }, - [DELL_PRECISION_490] = { - .fan_mult = 1, - .fan_max = I8K_FAN_TURBO, - }, - [DELL_STUDIO] = { - .fan_mult = 1, - .fan_max = I8K_FAN_HIGH, - }, - [DELL_XPS] = { - .fan_mult = 1, - .fan_max = I8K_FAN_HIGH, - }, -}; - -static struct dmi_system_id i8k_dmi_table[] __initdata = { - { - .ident = "Dell Inspiron", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer"), - DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron"), - }, - }, - { - .ident = "Dell Latitude", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer"), - DMI_MATCH(DMI_PRODUCT_NAME, "Latitude"), - }, - }, - { - .ident = "Dell Inspiron 2", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron"), - }, - }, - { - .ident = "Dell Latitude D520", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Latitude D520"), - }, - .driver_data = (void *)&i8k_config_data[DELL_LATITUDE_D520], - }, - { - .ident = "Dell Latitude 2", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Latitude"), - }, - }, - { /* UK Inspiron 6400 */ - .ident = "Dell Inspiron 3", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MM061"), - }, - }, - { - .ident = "Dell Inspiron 3", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MP061"), - }, - }, - { - .ident = "Dell Precision 490", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, - "Precision WorkStation 490"), - }, - .driver_data = (void *)&i8k_config_data[DELL_PRECISION_490], - }, - { - .ident = "Dell Precision", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Precision"), - }, - }, - { - .ident = "Dell Vostro", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Vostro"), - }, - }, - { - .ident = "Dell XPS421", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "XPS L421X"), - }, - }, - { - .ident = "Dell Studio", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Studio"), - }, - .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], - }, - { } -}; - -MODULE_DEVICE_TABLE(dmi, i8k_dmi_table); - -/* - * Probe for the presence of a supported laptop. - */ -static int __init i8k_probe(void) -{ - const struct dmi_system_id *id; - int fan, ret; - - /* - * Get DMI information - */ - if (!dmi_check_system(i8k_dmi_table)) { - if (!ignore_dmi && !force) - return -ENODEV; - - pr_info("not running on a supported Dell system.\n"); - pr_info("vendor=%s, model=%s, version=%s\n", - i8k_get_dmi_data(DMI_SYS_VENDOR), - i8k_get_dmi_data(DMI_PRODUCT_NAME), - i8k_get_dmi_data(DMI_BIOS_VERSION)); - } - - strlcpy(bios_version, i8k_get_dmi_data(DMI_BIOS_VERSION), - sizeof(bios_version)); - - /* - * Get SMM Dell signature - */ - if (i8k_get_dell_signature(I8K_SMM_GET_DELL_SIG1) && - i8k_get_dell_signature(I8K_SMM_GET_DELL_SIG2)) { - pr_err("unable to get SMM Dell signature\n"); - if (!force) - return -ENODEV; - } - - /* - * 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 && 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; -} - -static int __init i8k_init(void) -{ - struct proc_dir_entry *proc_i8k; - int err; - - /* Are we running on an supported laptop? */ - if (i8k_probe()) - return -ENODEV; - - /* Register the proc entry */ - proc_i8k = proc_create("i8k", 0, NULL, &i8k_fops); - if (!proc_i8k) - return -ENOENT; - - err = i8k_init_hwmon(); - if (err) - goto exit_remove_proc; - - return 0; - - exit_remove_proc: - remove_proc_entry("i8k", NULL); - return err; -} - -static void __exit i8k_exit(void) -{ - hwmon_device_unregister(i8k_hwmon_dev); - remove_proc_entry("i8k", NULL); -} - -module_init(i8k_init); -module_exit(i8k_exit); diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 9bb592872532..bf75f6361773 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -2000,7 +2000,7 @@ static int smi_ipmb_proc_show(struct seq_file *m, void *v) seq_printf(m, " %x", intf->channels[i].address); seq_putc(m, '\n'); - return seq_has_overflowed(m); + return 0; } static int smi_ipmb_proc_open(struct inode *inode, struct file *file) @@ -2023,7 +2023,7 @@ static int smi_version_proc_show(struct seq_file *m, void *v) ipmi_version_major(&intf->bmc->id), ipmi_version_minor(&intf->bmc->id)); - return seq_has_overflowed(m); + return 0; } static int smi_version_proc_open(struct inode *inode, struct file *file) diff --git a/drivers/char/ipmi/ipmi_powernv.c b/drivers/char/ipmi/ipmi_powernv.c index 8753b0f6a317..9b409c0f14f7 100644 --- a/drivers/char/ipmi/ipmi_powernv.c +++ b/drivers/char/ipmi/ipmi_powernv.c @@ -15,6 +15,8 @@ #include <linux/list.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_irq.h> +#include <linux/interrupt.h> #include <asm/opal.h> @@ -23,8 +25,7 @@ struct ipmi_smi_powernv { u64 interface_id; struct ipmi_device_id ipmi_id; ipmi_smi_t intf; - u64 event; - struct notifier_block event_nb; + unsigned int irq; /** * We assume that there can only be one outstanding request, so @@ -197,15 +198,12 @@ static struct ipmi_smi_handlers ipmi_powernv_smi_handlers = { .poll = ipmi_powernv_poll, }; -static int ipmi_opal_event(struct notifier_block *nb, - unsigned long events, void *change) +static irqreturn_t ipmi_opal_event(int irq, void *data) { - struct ipmi_smi_powernv *smi = container_of(nb, - struct ipmi_smi_powernv, event_nb); + struct ipmi_smi_powernv *smi = data; - if (events & smi->event) - ipmi_powernv_recv(smi); - return 0; + ipmi_powernv_recv(smi); + return IRQ_HANDLED; } static int ipmi_powernv_probe(struct platform_device *pdev) @@ -240,13 +238,16 @@ static int ipmi_powernv_probe(struct platform_device *pdev) goto err_free; } - ipmi->event = 1ull << prop; - ipmi->event_nb.notifier_call = ipmi_opal_event; + ipmi->irq = irq_of_parse_and_map(dev->of_node, 0); + if (!ipmi->irq) { + dev_info(dev, "Unable to map irq from device tree\n"); + ipmi->irq = opal_event_request(prop); + } - rc = opal_notifier_register(&ipmi->event_nb); - if (rc) { - dev_warn(dev, "OPAL notifier registration failed (%d)\n", rc); - goto err_free; + if (request_irq(ipmi->irq, ipmi_opal_event, IRQ_TYPE_LEVEL_HIGH, + "opal-ipmi", ipmi)) { + dev_warn(dev, "Unable to request irq\n"); + goto err_dispose; } ipmi->opal_msg = devm_kmalloc(dev, @@ -271,7 +272,9 @@ static int ipmi_powernv_probe(struct platform_device *pdev) err_free_msg: devm_kfree(dev, ipmi->opal_msg); err_unregister: - opal_notifier_unregister(&ipmi->event_nb); + free_irq(ipmi->irq, ipmi); +err_dispose: + irq_dispose_mapping(ipmi->irq); err_free: devm_kfree(dev, ipmi); return rc; @@ -282,7 +285,9 @@ static int ipmi_powernv_remove(struct platform_device *pdev) struct ipmi_smi_powernv *smi = dev_get_drvdata(&pdev->dev); ipmi_unregister_smi(smi->intf); - opal_notifier_unregister(&smi->event_nb); + free_irq(smi->irq, smi); + irq_dispose_mapping(smi->irq); + return 0; } diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 5e90a18afbaf..8a45e92ff60c 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -942,8 +942,7 @@ static void sender(void *send_info, * If we are running to completion, start it and run * transactions until everything is clear. */ - smi_info->curr_msg = msg; - smi_info->waiting_msg = NULL; + smi_info->waiting_msg = msg; /* * Run to completion means we are single-threaded, no @@ -2244,7 +2243,7 @@ static int ipmi_pnp_probe(struct pnp_dev *dev, acpi_handle handle; acpi_status status; unsigned long long tmp; - int rv; + int rv = -EINVAL; acpi_dev = pnp_acpi_device(dev); if (!acpi_dev) @@ -2262,8 +2261,10 @@ static int ipmi_pnp_probe(struct pnp_dev *dev, /* _IFT tells us the interface type: KCS, BT, etc */ status = acpi_evaluate_integer(handle, "_IFT", NULL, &tmp); - if (ACPI_FAILURE(status)) + if (ACPI_FAILURE(status)) { + dev_err(&dev->dev, "Could not find ACPI IPMI interface type\n"); goto err_free; + } switch (tmp) { case 1: @@ -2276,6 +2277,7 @@ static int ipmi_pnp_probe(struct pnp_dev *dev, info->si_type = SI_BT; break; case 4: /* SSIF, just ignore */ + rv = -ENODEV; goto err_free; default: dev_info(&dev->dev, "unknown IPMI type %lld\n", tmp); @@ -2336,7 +2338,7 @@ static int ipmi_pnp_probe(struct pnp_dev *dev, err_free: kfree(info); - return -EINVAL; + return rv; } static void ipmi_pnp_remove(struct pnp_dev *dev) @@ -3080,7 +3082,7 @@ static int smi_type_proc_show(struct seq_file *m, void *v) seq_printf(m, "%s\n", si_to_str[smi->si_type]); - return seq_has_overflowed(m); + return 0; } static int smi_type_proc_open(struct inode *inode, struct file *file) @@ -3153,7 +3155,7 @@ static int smi_params_proc_show(struct seq_file *m, void *v) smi->irq, smi->slave_addr); - return seq_has_overflowed(m); + return 0; } static int smi_params_proc_open(struct inode *inode, struct file *file) diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c index f40e3bd2c69c..207689c444a8 100644 --- a/drivers/char/ipmi/ipmi_ssif.c +++ b/drivers/char/ipmi/ipmi_ssif.c @@ -31,7 +31,6 @@ * interface into the I2C driver, I believe. */ -#include <linux/version.h> #if defined(MODVERSIONS) #include <linux/modversions.h> #endif @@ -166,6 +165,9 @@ enum ssif_stat_indexes { /* Number of watchdog pretimeouts. */ SSIF_STAT_watchdog_pretimeouts, + /* Number of alers received. */ + SSIF_STAT_alerts, + /* Always add statistics before this value, it must be last. */ SSIF_NUM_STATS }; @@ -214,7 +216,16 @@ struct ssif_info { #define WDT_PRE_TIMEOUT_INT 0x08 unsigned char msg_flags; + u8 global_enables; bool has_event_buffer; + bool supports_alert; + + /* + * Used to tell what we should do with alerts. If we are + * waiting on a response, read the data immediately. + */ + bool got_alert; + bool waiting_alert; /* * If set to true, this will request events the next time the @@ -478,13 +489,13 @@ static int ipmi_ssif_thread(void *data) if (ssif_info->i2c_read_write == I2C_SMBUS_WRITE) { result = i2c_smbus_write_block_data( - ssif_info->client, SSIF_IPMI_REQUEST, + ssif_info->client, ssif_info->i2c_command, ssif_info->i2c_data[0], ssif_info->i2c_data + 1); ssif_info->done_handler(ssif_info, result, NULL, 0); } else { result = i2c_smbus_read_block_data( - ssif_info->client, SSIF_IPMI_RESPONSE, + ssif_info->client, ssif_info->i2c_command, ssif_info->i2c_data); if (result < 0) ssif_info->done_handler(ssif_info, result, @@ -518,15 +529,12 @@ static int ssif_i2c_send(struct ssif_info *ssif_info, static void msg_done_handler(struct ssif_info *ssif_info, int result, unsigned char *data, unsigned int len); -static void retry_timeout(unsigned long data) +static void start_get(struct ssif_info *ssif_info) { - struct ssif_info *ssif_info = (void *) data; int rv; - if (ssif_info->stopping) - return; - ssif_info->rtc_us_timer = 0; + ssif_info->multi_pos = 0; rv = ssif_i2c_send(ssif_info, msg_done_handler, I2C_SMBUS_READ, SSIF_IPMI_RESPONSE, @@ -540,6 +548,46 @@ static void retry_timeout(unsigned long data) } } +static void retry_timeout(unsigned long data) +{ + struct ssif_info *ssif_info = (void *) data; + unsigned long oflags, *flags; + bool waiting; + + if (ssif_info->stopping) + return; + + flags = ipmi_ssif_lock_cond(ssif_info, &oflags); + waiting = ssif_info->waiting_alert; + ssif_info->waiting_alert = false; + ipmi_ssif_unlock_cond(ssif_info, flags); + + if (waiting) + start_get(ssif_info); +} + + +static void ssif_alert(struct i2c_client *client, unsigned int data) +{ + struct ssif_info *ssif_info = i2c_get_clientdata(client); + unsigned long oflags, *flags; + bool do_get = false; + + ssif_inc_stat(ssif_info, alerts); + + flags = ipmi_ssif_lock_cond(ssif_info, &oflags); + if (ssif_info->waiting_alert) { + ssif_info->waiting_alert = false; + del_timer(&ssif_info->retry_timer); + do_get = true; + } else if (ssif_info->curr_msg) { + ssif_info->got_alert = true; + } + ipmi_ssif_unlock_cond(ssif_info, flags); + if (do_get) + start_get(ssif_info); +} + static int start_resend(struct ssif_info *ssif_info); static void msg_done_handler(struct ssif_info *ssif_info, int result, @@ -559,9 +607,12 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result, if (ssif_info->retries_left > 0) { ssif_inc_stat(ssif_info, receive_retries); + flags = ipmi_ssif_lock_cond(ssif_info, &oflags); + ssif_info->waiting_alert = true; + ssif_info->rtc_us_timer = SSIF_MSG_USEC; mod_timer(&ssif_info->retry_timer, jiffies + SSIF_MSG_JIFFIES); - ssif_info->rtc_us_timer = SSIF_MSG_USEC; + ipmi_ssif_unlock_cond(ssif_info, flags); return; } @@ -581,9 +632,9 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result, ssif_inc_stat(ssif_info, received_message_parts); /* Remove the multi-part read marker. */ - for (i = 0; i < (len-2); i++) - ssif_info->data[i] = data[i+2]; len -= 2; + for (i = 0; i < len; i++) + ssif_info->data[i] = data[i+2]; ssif_info->multi_len = len; ssif_info->multi_pos = 1; @@ -610,9 +661,9 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result, goto continue_op; } - blocknum = data[ssif_info->multi_len]; + blocknum = data[0]; - if (ssif_info->multi_len+len-1 > IPMI_MAX_MSG_LENGTH) { + if (ssif_info->multi_len + len - 1 > IPMI_MAX_MSG_LENGTH) { /* Received message too big, abort the operation. */ result = -E2BIG; if (ssif_info->ssif_debug & SSIF_DEBUG_MSG) @@ -622,15 +673,15 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result, } /* Remove the blocknum from the data. */ - for (i = 0; i < (len-1); i++) - ssif_info->data[i+ssif_info->multi_len] = data[i+1]; len--; + for (i = 0; i < len; i++) + ssif_info->data[i + ssif_info->multi_len] = data[i + 1]; ssif_info->multi_len += len; if (blocknum == 0xff) { /* End of read */ len = ssif_info->multi_len; data = ssif_info->data; - } else if ((blocknum+1) != ssif_info->multi_pos) { + } else if (blocknum + 1 != ssif_info->multi_pos) { /* * Out of sequence block, just abort. Block * numbers start at zero for the second block, @@ -650,7 +701,7 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result, if (rv < 0) { if (ssif_info->ssif_debug & SSIF_DEBUG_MSG) pr_info(PFX - "Error from i2c_non_blocking_op(2)\n"); + "Error from ssif_i2c_send\n"); result = -EIO; } else @@ -830,7 +881,11 @@ static void msg_written_handler(struct ssif_info *ssif_info, int result, } if (ssif_info->multi_data) { - /* In the middle of a multi-data write. */ + /* + * In the middle of a multi-data write. See the comment + * in the SSIF_MULTI_n_PART case in the probe function + * for details on the intricacies of this. + */ int left; ssif_inc_stat(ssif_info, sent_messages_parts); @@ -864,15 +919,32 @@ static void msg_written_handler(struct ssif_info *ssif_info, int result, msg_done_handler(ssif_info, -EIO, NULL, 0); } } else { + unsigned long oflags, *flags; + bool got_alert; + ssif_inc_stat(ssif_info, sent_messages); ssif_inc_stat(ssif_info, sent_messages_parts); - /* Wait a jiffie then request the next message */ - ssif_info->retries_left = SSIF_RECV_RETRIES; - ssif_info->rtc_us_timer = SSIF_MSG_PART_USEC; - mod_timer(&ssif_info->retry_timer, - jiffies + SSIF_MSG_PART_JIFFIES); - return; + flags = ipmi_ssif_lock_cond(ssif_info, &oflags); + got_alert = ssif_info->got_alert; + if (got_alert) { + ssif_info->got_alert = false; + ssif_info->waiting_alert = false; + } + + if (got_alert) { + ipmi_ssif_unlock_cond(ssif_info, flags); + /* The alert already happened, try now. */ + retry_timeout((unsigned long) ssif_info); + } else { + /* Wait a jiffie then request the next message */ + ssif_info->waiting_alert = true; + ssif_info->retries_left = SSIF_RECV_RETRIES; + ssif_info->rtc_us_timer = SSIF_MSG_PART_USEC; + mod_timer(&ssif_info->retry_timer, + jiffies + SSIF_MSG_PART_JIFFIES); + ipmi_ssif_unlock_cond(ssif_info, flags); + } } } @@ -881,6 +953,8 @@ static int start_resend(struct ssif_info *ssif_info) int rv; int command; + ssif_info->got_alert = false; + if (ssif_info->data_len > 32) { command = SSIF_IPMI_MULTI_PART_REQUEST_START; ssif_info->multi_data = ssif_info->data; @@ -915,7 +989,7 @@ static int start_send(struct ssif_info *ssif_info, return -E2BIG; ssif_info->retries_left = SSIF_SEND_RETRIES; - memcpy(ssif_info->data+1, data, len); + memcpy(ssif_info->data + 1, data, len); ssif_info->data_len = len; return start_resend(ssif_info); } @@ -1200,7 +1274,7 @@ static int smi_type_proc_show(struct seq_file *m, void *v) { seq_puts(m, "ssif\n"); - return seq_has_overflowed(m); + return 0; } static int smi_type_proc_open(struct inode *inode, struct file *file) @@ -1243,6 +1317,8 @@ static int smi_stats_proc_show(struct seq_file *m, void *v) ssif_get_stat(ssif_info, events)); seq_printf(m, "watchdog_pretimeouts: %u\n", ssif_get_stat(ssif_info, watchdog_pretimeouts)); + seq_printf(m, "alerts: %u\n", + ssif_get_stat(ssif_info, alerts)); return 0; } @@ -1258,6 +1334,23 @@ static const struct file_operations smi_stats_proc_ops = { .release = single_release, }; +static int strcmp_nospace(char *s1, char *s2) +{ + while (*s1 && *s2) { + while (isspace(*s1)) + s1++; + while (isspace(*s2)) + s2++; + if (*s1 > *s2) + return 1; + if (*s1 < *s2) + return -1; + s1++; + s2++; + } + return 0; +} + static struct ssif_addr_info *ssif_info_find(unsigned short addr, char *adapter_name, bool match_null_name) @@ -1272,8 +1365,10 @@ restart: /* One is NULL and one is not */ continue; } - if (strcmp(info->adapter_name, adapter_name)) - /* Names to not match */ + if (adapter_name && + strcmp_nospace(info->adapter_name, + adapter_name)) + /* Names do not match */ continue; } found = info; @@ -1306,6 +1401,12 @@ static bool check_acpi(struct ssif_info *ssif_info, struct device *dev) return false; } +/* + * Global enables we care about. + */ +#define GLOBAL_ENABLES_MASK (IPMI_BMC_EVT_MSG_BUFF | IPMI_BMC_RCV_MSG_INTR | \ + IPMI_BMC_EVT_MSG_INTR) + static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) { unsigned char msg[3]; @@ -1391,13 +1492,33 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) break; case SSIF_MULTI_2_PART: - if (ssif_info->max_xmit_msg_size > 64) - ssif_info->max_xmit_msg_size = 64; + if (ssif_info->max_xmit_msg_size > 63) + ssif_info->max_xmit_msg_size = 63; if (ssif_info->max_recv_msg_size > 62) ssif_info->max_recv_msg_size = 62; break; case SSIF_MULTI_n_PART: + /* + * The specification is rather confusing at + * this point, but I think I understand what + * is meant. At least I have a workable + * solution. With multi-part messages, you + * cannot send a message that is a multiple of + * 32-bytes in length, because the start and + * middle messages are 32-bytes and the end + * message must be at least one byte. You + * can't fudge on an extra byte, that would + * screw up things like fru data writes. So + * we limit the length to 63 bytes. That way + * a 32-byte message gets sent as a single + * part. A larger message will be a 32-byte + * start and the next message is always going + * to be 1-31 bytes in length. Not ideal, but + * it should work. + */ + if (ssif_info->max_xmit_msg_size > 63) + ssif_info->max_xmit_msg_size = 63; break; default: @@ -1407,7 +1528,7 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) } else { no_support: /* Assume no multi-part or PEC support */ - pr_info(PFX "Error fetching SSIF: %d %d %2.2x, your system probably doesn't support this command so using defaults\n", + pr_info(PFX "Error fetching SSIF: %d %d %2.2x, your system probably doesn't support this command so using defaults\n", rv, len, resp[2]); ssif_info->max_xmit_msg_size = 32; @@ -1436,6 +1557,8 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) goto found; } + ssif_info->global_enables = resp[3]; + if (resp[3] & IPMI_BMC_EVT_MSG_BUFF) { ssif_info->has_event_buffer = true; /* buffer is already enabled, nothing to do. */ @@ -1444,18 +1567,37 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) msg[0] = IPMI_NETFN_APP_REQUEST << 2; msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD; - msg[2] = resp[3] | IPMI_BMC_EVT_MSG_BUFF; + msg[2] = ssif_info->global_enables | IPMI_BMC_EVT_MSG_BUFF; rv = do_cmd(client, 3, msg, &len, resp); if (rv || (len < 2)) { - pr_warn(PFX "Error getting global enables: %d %d %2.2x\n", + pr_warn(PFX "Error setting global enables: %d %d %2.2x\n", rv, len, resp[2]); rv = 0; /* Not fatal */ goto found; } - if (resp[2] == 0) + if (resp[2] == 0) { /* A successful return means the event buffer is supported. */ ssif_info->has_event_buffer = true; + ssif_info->global_enables |= IPMI_BMC_EVT_MSG_BUFF; + } + + msg[0] = IPMI_NETFN_APP_REQUEST << 2; + msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD; + msg[2] = ssif_info->global_enables | IPMI_BMC_RCV_MSG_INTR; + rv = do_cmd(client, 3, msg, &len, resp); + if (rv || (len < 2)) { + pr_warn(PFX "Error setting global enables: %d %d %2.2x\n", + rv, len, resp[2]); + rv = 0; /* Not fatal */ + goto found; + } + + if (resp[2] == 0) { + /* A successful return means the alert is supported. */ + ssif_info->supports_alert = true; + ssif_info->global_enables |= IPMI_BMC_RCV_MSG_INTR; + } found: ssif_info->intf_num = atomic_inc_return(&next_intf); @@ -1813,6 +1955,7 @@ static struct i2c_driver ssif_i2c_driver = { }, .probe = ssif_probe, .remove = ssif_remove, + .alert = ssif_alert, .id_table = ssif_id, .detect = ssif_detect }; @@ -1832,7 +1975,7 @@ static int init_ipmi_ssif(void) rv = new_ssif_client(addr[i], adapter_name[i], dbg[i], slave_addrs[i], SI_HARDCODED); - if (!rv) + if (rv) pr_err(PFX "Couldn't add hardcoded device at addr 0x%x\n", addr[i]); diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 9fd5a91e0d81..fdb0f9b3fe45 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -117,14 +117,14 @@ static int misc_open(struct inode * inode, struct file * file) const struct file_operations *new_fops = NULL; mutex_lock(&misc_mtx); - + list_for_each_entry(c, &misc_list, list) { if (c->minor == minor) { - new_fops = fops_get(c->fops); + new_fops = fops_get(c->fops); break; } } - + if (!new_fops) { mutex_unlock(&misc_mtx); request_module("char-major-%d-%d", MISC_MAJOR, minor); @@ -167,7 +167,7 @@ static const struct file_operations misc_fops = { /** * misc_register - register a miscellaneous device * @misc: device structure - * + * * Register a miscellaneous device with the kernel. If the minor * number is set to %MISC_DYNAMIC_MINOR a minor number is assigned * and placed in the minor field of the structure. For other cases @@ -181,17 +181,18 @@ static const struct file_operations misc_fops = { * A zero is returned on success and a negative errno code for * failure. */ - + int misc_register(struct miscdevice * misc) { dev_t dev; int err = 0; + bool is_dynamic = (misc->minor == MISC_DYNAMIC_MINOR); INIT_LIST_HEAD(&misc->list); mutex_lock(&misc_mtx); - if (misc->minor == MISC_DYNAMIC_MINOR) { + if (is_dynamic) { int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS); if (i >= DYNAMIC_MINORS) { err = -EBUSY; @@ -216,9 +217,13 @@ int misc_register(struct miscdevice * misc) device_create_with_groups(misc_class, misc->parent, dev, misc, misc->groups, "%s", misc->name); if (IS_ERR(misc->this_device)) { - int i = DYNAMIC_MINORS - misc->minor - 1; - if (i < DYNAMIC_MINORS && i >= 0) - clear_bit(i, misc_minors); + if (is_dynamic) { + int i = DYNAMIC_MINORS - misc->minor - 1; + + if (i < DYNAMIC_MINORS && i >= 0) + clear_bit(i, misc_minors); + misc->minor = MISC_DYNAMIC_MINOR; + } err = PTR_ERR(misc->this_device); goto out; } diff --git a/drivers/char/msm_smd_pkt.c b/drivers/char/msm_smd_pkt.c deleted file mode 100644 index ba82a06d9684..000000000000 --- a/drivers/char/msm_smd_pkt.c +++ /dev/null @@ -1,465 +0,0 @@ -/* Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - */ -/* - * SMD Packet Driver -- Provides userspace interface to SMD packet ports. - */ - -#include <linux/slab.h> -#include <linux/cdev.h> -#include <linux/module.h> -#include <linux/fs.h> -#include <linux/device.h> -#include <linux/sched.h> -#include <linux/mutex.h> -#include <linux/delay.h> -#include <linux/uaccess.h> -#include <linux/workqueue.h> -#include <linux/poll.h> - -#include <mach/msm_smd.h> - -#define NUM_SMD_PKT_PORTS 9 -#define DEVICE_NAME "smdpkt" -#define MAX_BUF_SIZE 2048 - -struct smd_pkt_dev { - struct cdev cdev; - struct device *devicep; - - struct smd_channel *ch; - int open_count; - struct mutex ch_lock; - struct mutex rx_lock; - struct mutex tx_lock; - wait_queue_head_t ch_read_wait_queue; - wait_queue_head_t ch_opened_wait_queue; - - int i; - - unsigned char tx_buf[MAX_BUF_SIZE]; - unsigned char rx_buf[MAX_BUF_SIZE]; - int remote_open; - -} *smd_pkt_devp[NUM_SMD_PKT_PORTS]; - -struct class *smd_pkt_classp; -static dev_t smd_pkt_number; - -static int msm_smd_pkt_debug_enable; -module_param_named(debug_enable, msm_smd_pkt_debug_enable, - int, S_IRUGO | S_IWUSR | S_IWGRP); - -#ifdef DEBUG -#define D_DUMP_BUFFER(prestr, cnt, buf) do { \ - int i; \ - if (msm_smd_pkt_debug_enable) { \ - pr_debug("%s", prestr); \ - for (i = 0; i < cnt; i++) \ - pr_debug("%.2x", buf[i]); \ - pr_debug("\n"); \ - } \ - } while (0) -#else -#define D_DUMP_BUFFER(prestr, cnt, buf) do {} while (0) -#endif - -#ifdef DEBUG -#define DBG(x...) do { \ - if (msm_smd_pkt_debug_enable) \ - pr_debug(x); \ - } while (0) -#else -#define DBG(x...) do {} while (0) -#endif - -static void check_and_wakeup_reader(struct smd_pkt_dev *smd_pkt_devp) -{ - int sz; - - if (!smd_pkt_devp || !smd_pkt_devp->ch) - return; - - sz = smd_cur_packet_size(smd_pkt_devp->ch); - if (sz == 0) { - DBG("no packet\n"); - return; - } - if (sz > smd_read_avail(smd_pkt_devp->ch)) { - DBG("incomplete packet\n"); - return; - } - - DBG("waking up reader\n"); - wake_up_interruptible(&smd_pkt_devp->ch_read_wait_queue); -} - -static int smd_pkt_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - int r, bytes_read; - struct smd_pkt_dev *smd_pkt_devp; - struct smd_channel *chl; - - DBG("read %d bytes\n", count); - if (count > MAX_BUF_SIZE) - return -EINVAL; - - smd_pkt_devp = file->private_data; - if (!smd_pkt_devp || !smd_pkt_devp->ch) - return -EINVAL; - - chl = smd_pkt_devp->ch; -wait_for_packet: - r = wait_event_interruptible(smd_pkt_devp->ch_read_wait_queue, - (smd_cur_packet_size(chl) > 0 && - smd_read_avail(chl) >= - smd_cur_packet_size(chl))); - - if (r < 0) { - if (r != -ERESTARTSYS) - pr_err("wait returned %d\n", r); - return r; - } - - mutex_lock(&smd_pkt_devp->rx_lock); - - bytes_read = smd_cur_packet_size(smd_pkt_devp->ch); - if (bytes_read == 0 || - bytes_read < smd_read_avail(smd_pkt_devp->ch)) { - mutex_unlock(&smd_pkt_devp->rx_lock); - DBG("Nothing to read\n"); - goto wait_for_packet; - } - - if (bytes_read > count) { - mutex_unlock(&smd_pkt_devp->rx_lock); - pr_info("packet size %d > buffer size %d", bytes_read, count); - return -EINVAL; - } - - r = smd_read(smd_pkt_devp->ch, smd_pkt_devp->rx_buf, bytes_read); - if (r != bytes_read) { - mutex_unlock(&smd_pkt_devp->rx_lock); - pr_err("smd_read failed to read %d bytes: %d\n", bytes_read, r); - return -EIO; - } - - D_DUMP_BUFFER("read: ", bytes_read, smd_pkt_devp->rx_buf); - r = copy_to_user(buf, smd_pkt_devp->rx_buf, bytes_read); - mutex_unlock(&smd_pkt_devp->rx_lock); - if (r) { - pr_err("copy_to_user failed %d\n", r); - return -EFAULT; - } - - DBG("read complete %d bytes\n", bytes_read); - check_and_wakeup_reader(smd_pkt_devp); - - return bytes_read; -} - -static int smd_pkt_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - int r; - struct smd_pkt_dev *smd_pkt_devp; - - if (count > MAX_BUF_SIZE) - return -EINVAL; - - DBG("writing %d bytes\n", count); - - smd_pkt_devp = file->private_data; - if (!smd_pkt_devp || !smd_pkt_devp->ch) - return -EINVAL; - - mutex_lock(&smd_pkt_devp->tx_lock); - if (smd_write_avail(smd_pkt_devp->ch) < count) { - mutex_unlock(&smd_pkt_devp->tx_lock); - DBG("Not enough space to write\n"); - return -ENOMEM; - } - - D_DUMP_BUFFER("write: ", count, buf); - r = copy_from_user(smd_pkt_devp->tx_buf, buf, count); - if (r) { - mutex_unlock(&smd_pkt_devp->tx_lock); - pr_err("copy_from_user failed %d\n", r); - return -EFAULT; - } - - r = smd_write(smd_pkt_devp->ch, smd_pkt_devp->tx_buf, count); - if (r != count) { - mutex_unlock(&smd_pkt_devp->tx_lock); - pr_err("smd_write failed to write %d bytes: %d.\n", count, r); - return -EIO; - } - mutex_unlock(&smd_pkt_devp->tx_lock); - - DBG("wrote %d bytes\n", count); - return count; -} - -static unsigned int smd_pkt_poll(struct file *file, poll_table *wait) -{ - struct smd_pkt_dev *smd_pkt_devp; - unsigned int mask = 0; - - smd_pkt_devp = file->private_data; - if (!smd_pkt_devp) - return POLLERR; - - DBG("poll waiting\n"); - poll_wait(file, &smd_pkt_devp->ch_read_wait_queue, wait); - if (smd_read_avail(smd_pkt_devp->ch)) - mask |= POLLIN | POLLRDNORM; - - DBG("poll return\n"); - return mask; -} - -static void smd_pkt_ch_notify(void *priv, unsigned event) -{ - struct smd_pkt_dev *smd_pkt_devp = priv; - - if (smd_pkt_devp->ch == 0) - return; - - switch (event) { - case SMD_EVENT_DATA: - DBG("data\n"); - check_and_wakeup_reader(smd_pkt_devp); - break; - - case SMD_EVENT_OPEN: - DBG("remote open\n"); - smd_pkt_devp->remote_open = 1; - wake_up_interruptible(&smd_pkt_devp->ch_opened_wait_queue); - break; - - case SMD_EVENT_CLOSE: - smd_pkt_devp->remote_open = 0; - pr_info("remote closed\n"); - break; - - default: - pr_err("unknown event %d\n", event); - break; - } -} - -static char *smd_pkt_dev_name[] = { - "smdcntl0", - "smdcntl1", - "smdcntl2", - "smdcntl3", - "smdcntl4", - "smdcntl5", - "smdcntl6", - "smdcntl7", - "smd22", -}; - -static char *smd_ch_name[] = { - "DATA5_CNTL", - "DATA6_CNTL", - "DATA7_CNTL", - "DATA8_CNTL", - "DATA9_CNTL", - "DATA12_CNTL", - "DATA13_CNTL", - "DATA14_CNTL", - "DATA22", -}; - -static int smd_pkt_open(struct inode *inode, struct file *file) -{ - int r = 0; - struct smd_pkt_dev *smd_pkt_devp; - - smd_pkt_devp = container_of(inode->i_cdev, struct smd_pkt_dev, cdev); - if (!smd_pkt_devp) - return -EINVAL; - - file->private_data = smd_pkt_devp; - - mutex_lock(&smd_pkt_devp->ch_lock); - if (smd_pkt_devp->open_count == 0) { - r = smd_open(smd_ch_name[smd_pkt_devp->i], - &smd_pkt_devp->ch, smd_pkt_devp, - smd_pkt_ch_notify); - if (r < 0) { - pr_err("smd_open failed for %s, %d\n", - smd_ch_name[smd_pkt_devp->i], r); - goto out; - } - - r = wait_event_interruptible_timeout( - smd_pkt_devp->ch_opened_wait_queue, - smd_pkt_devp->remote_open, - msecs_to_jiffies(2 * HZ)); - if (r == 0) - r = -ETIMEDOUT; - - if (r < 0) { - pr_err("wait returned %d\n", r); - smd_close(smd_pkt_devp->ch); - smd_pkt_devp->ch = 0; - } else { - smd_pkt_devp->open_count++; - r = 0; - } - } -out: - mutex_unlock(&smd_pkt_devp->ch_lock); - return r; -} - -static int smd_pkt_release(struct inode *inode, struct file *file) -{ - int r = 0; - struct smd_pkt_dev *smd_pkt_devp = file->private_data; - - if (!smd_pkt_devp) - return -EINVAL; - - mutex_lock(&smd_pkt_devp->ch_lock); - if (--smd_pkt_devp->open_count == 0) { - r = smd_close(smd_pkt_devp->ch); - smd_pkt_devp->ch = 0; - } - mutex_unlock(&smd_pkt_devp->ch_lock); - - return r; -} - -static const struct file_operations smd_pkt_fops = { - .owner = THIS_MODULE, - .open = smd_pkt_open, - .release = smd_pkt_release, - .read = smd_pkt_read, - .write = smd_pkt_write, - .poll = smd_pkt_poll, -}; - -static int __init smd_pkt_init(void) -{ - int i; - int r; - - r = alloc_chrdev_region(&smd_pkt_number, 0, - NUM_SMD_PKT_PORTS, DEVICE_NAME); - if (r) { - pr_err("alloc_chrdev_region() failed %d\n", r); - return r; - } - - smd_pkt_classp = class_create(THIS_MODULE, DEVICE_NAME); - if (IS_ERR(smd_pkt_classp)) { - r = PTR_ERR(smd_pkt_classp); - pr_err("class_create() failed %d\n", r); - goto unreg_chardev; - } - - for (i = 0; i < NUM_SMD_PKT_PORTS; ++i) { - smd_pkt_devp[i] = kzalloc(sizeof(struct smd_pkt_dev), - GFP_KERNEL); - if (!smd_pkt_devp[i]) { - pr_err("kmalloc() failed\n"); - goto clean_cdevs; - } - - smd_pkt_devp[i]->i = i; - - init_waitqueue_head(&smd_pkt_devp[i]->ch_read_wait_queue); - smd_pkt_devp[i]->remote_open = 0; - init_waitqueue_head(&smd_pkt_devp[i]->ch_opened_wait_queue); - - mutex_init(&smd_pkt_devp[i]->ch_lock); - mutex_init(&smd_pkt_devp[i]->rx_lock); - mutex_init(&smd_pkt_devp[i]->tx_lock); - - cdev_init(&smd_pkt_devp[i]->cdev, &smd_pkt_fops); - smd_pkt_devp[i]->cdev.owner = THIS_MODULE; - - r = cdev_add(&smd_pkt_devp[i]->cdev, - (smd_pkt_number + i), 1); - if (r) { - pr_err("cdev_add() failed %d\n", r); - kfree(smd_pkt_devp[i]); - goto clean_cdevs; - } - - smd_pkt_devp[i]->devicep = - device_create(smd_pkt_classp, NULL, - (smd_pkt_number + i), NULL, - smd_pkt_dev_name[i]); - if (IS_ERR(smd_pkt_devp[i]->devicep)) { - r = PTR_ERR(smd_pkt_devp[i]->devicep); - pr_err("device_create() failed %d\n", r); - cdev_del(&smd_pkt_devp[i]->cdev); - kfree(smd_pkt_devp[i]); - goto clean_cdevs; - } - - } - - pr_info("SMD Packet Port Driver Initialized.\n"); - return 0; - -clean_cdevs: - if (i > 0) { - while (--i >= 0) { - mutex_destroy(&smd_pkt_devp[i]->ch_lock); - mutex_destroy(&smd_pkt_devp[i]->rx_lock); - mutex_destroy(&smd_pkt_devp[i]->tx_lock); - cdev_del(&smd_pkt_devp[i]->cdev); - kfree(smd_pkt_devp[i]); - device_destroy(smd_pkt_classp, - MKDEV(MAJOR(smd_pkt_number), i)); - } - } - - class_destroy(smd_pkt_classp); -unreg_chardev: - unregister_chrdev_region(MAJOR(smd_pkt_number), NUM_SMD_PKT_PORTS); - return r; -} -module_init(smd_pkt_init); - -static void __exit smd_pkt_cleanup(void) -{ - int i; - - for (i = 0; i < NUM_SMD_PKT_PORTS; ++i) { - mutex_destroy(&smd_pkt_devp[i]->ch_lock); - mutex_destroy(&smd_pkt_devp[i]->rx_lock); - mutex_destroy(&smd_pkt_devp[i]->tx_lock); - cdev_del(&smd_pkt_devp[i]->cdev); - kfree(smd_pkt_devp[i]); - device_destroy(smd_pkt_classp, - MKDEV(MAJOR(smd_pkt_number), i)); - } - - class_destroy(smd_pkt_classp); - unregister_chrdev_region(MAJOR(smd_pkt_number), NUM_SMD_PKT_PORTS); -} -module_exit(smd_pkt_cleanup); - -MODULE_DESCRIPTION("MSM Shared Memory Packet Port"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c index 8dd48a2be911..fc061f7c2bd1 100644 --- a/drivers/char/pcmcia/cm4040_cs.c +++ b/drivers/char/pcmcia/cm4040_cs.c @@ -532,9 +532,8 @@ static int reader_config(struct pcmcia_device *link, int devno) fail_rc = pcmcia_enable_device(link); if (fail_rc != 0) { - dev_printk(KERN_INFO, &link->dev, - "pcmcia_enable_device failed 0x%x\n", - fail_rc); + dev_info(&link->dev, "pcmcia_enable_device failed 0x%x\n", + fail_rc); goto cs_release; } diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 0ea9986059af..7680d5213ff8 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -437,7 +437,7 @@ static int mgslpc_device_count = 0; * .text section address and breakpoint on module load. * This is useful for use with gdb and add-symbol-file command. */ -static bool break_on_load=0; +static bool break_on_load; /* * Driver major number, defaults to zero to get auto diff --git a/drivers/char/random.c b/drivers/char/random.c index 9cd6968e2f92..d0da5d852d41 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -409,6 +409,9 @@ static DECLARE_WAIT_QUEUE_HEAD(random_write_wait); static DECLARE_WAIT_QUEUE_HEAD(urandom_init_wait); static struct fasync_struct *fasync; +static DEFINE_SPINLOCK(random_ready_list_lock); +static LIST_HEAD(random_ready_list); + /********************************************************************** * * OS independent entropy store. Here are the functions which handle @@ -589,6 +592,22 @@ static void fast_mix(struct fast_pool *f) f->count++; } +static void process_random_ready_list(void) +{ + unsigned long flags; + struct random_ready_callback *rdy, *tmp; + + spin_lock_irqsave(&random_ready_list_lock, flags); + list_for_each_entry_safe(rdy, tmp, &random_ready_list, list) { + struct module *owner = rdy->owner; + + list_del_init(&rdy->list); + rdy->func(rdy); + module_put(owner); + } + spin_unlock_irqrestore(&random_ready_list_lock, flags); +} + /* * Credit (or debit) the entropy store with n bits of entropy. * Use credit_entropy_bits_safe() if the value comes from userspace @@ -660,7 +679,8 @@ retry: r->entropy_total = 0; if (r == &nonblocking_pool) { prandom_reseed_late(); - wake_up_interruptible(&urandom_init_wait); + process_random_ready_list(); + wake_up_all(&urandom_init_wait); pr_notice("random: %s pool is initialized\n", r->name); } } @@ -1245,6 +1265,64 @@ void get_random_bytes(void *buf, int nbytes) EXPORT_SYMBOL(get_random_bytes); /* + * Add a callback function that will be invoked when the nonblocking + * pool is initialised. + * + * returns: 0 if callback is successfully added + * -EALREADY if pool is already initialised (callback not called) + * -ENOENT if module for callback is not alive + */ +int add_random_ready_callback(struct random_ready_callback *rdy) +{ + struct module *owner; + unsigned long flags; + int err = -EALREADY; + + if (likely(nonblocking_pool.initialized)) + return err; + + owner = rdy->owner; + if (!try_module_get(owner)) + return -ENOENT; + + spin_lock_irqsave(&random_ready_list_lock, flags); + if (nonblocking_pool.initialized) + goto out; + + owner = NULL; + + list_add(&rdy->list, &random_ready_list); + err = 0; + +out: + spin_unlock_irqrestore(&random_ready_list_lock, flags); + + module_put(owner); + + return err; +} +EXPORT_SYMBOL(add_random_ready_callback); + +/* + * Delete a previously registered readiness callback function. + */ +void del_random_ready_callback(struct random_ready_callback *rdy) +{ + unsigned long flags; + struct module *owner = NULL; + + spin_lock_irqsave(&random_ready_list_lock, flags); + if (!list_empty(&rdy->list)) { + list_del_init(&rdy->list); + owner = rdy->owner; + } + spin_unlock_irqrestore(&random_ready_list_lock, flags); + + module_put(owner); +} +EXPORT_SYMBOL(del_random_ready_callback); + +/* * This function will use the architecture-specific hardware random * number generator if it is available. The arch-specific hw RNG will * almost certainly be faster than what we can do in software, but it diff --git a/drivers/char/raw.c b/drivers/char/raw.c index 5fc291c6157e..60316fbaf295 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -12,6 +12,7 @@ #include <linux/fs.h> #include <linux/major.h> #include <linux/blkdev.h> +#include <linux/backing-dev.h> #include <linux/module.h> #include <linux/raw.h> #include <linux/capability.h> diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c index 8bab59292a0d..8a80ead8d316 100644 --- a/drivers/char/snsc.c +++ b/drivers/char/snsc.c @@ -198,7 +198,7 @@ scdrv_read(struct file *file, char __user *buf, size_t count, loff_t *f_pos) add_wait_queue(&sd->sd_rq, &wait); spin_unlock_irqrestore(&sd->sd_rlock, flags); - schedule_timeout(SCDRV_TIMEOUT); + schedule_timeout(msecs_to_jiffies(SCDRV_TIMEOUT)); remove_wait_queue(&sd->sd_rq, &wait); if (signal_pending(current)) { @@ -294,7 +294,7 @@ scdrv_write(struct file *file, const char __user *buf, add_wait_queue(&sd->sd_wq, &wait); spin_unlock_irqrestore(&sd->sd_wlock, flags); - schedule_timeout(SCDRV_TIMEOUT); + schedule_timeout(msecs_to_jiffies(SCDRV_TIMEOUT)); remove_wait_queue(&sd->sd_wq, &wait); if (signal_pending(current)) { diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 50754d203310..d2406fe25533 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1492,8 +1492,8 @@ static int add_port(struct ports_device *portdev, u32 id) * Finally, create the debugfs file that we can use to * inspect a port's state at any time */ - sprintf(debugfs_name, "vport%up%u", - port->portdev->vdev->index, id); + snprintf(debugfs_name, sizeof(debugfs_name), "vport%up%u", + port->portdev->vdev->index, id); port->debugfs_file = debugfs_create_file(debugfs_name, 0444, pdrvdata.debugfs_dir, port, diff --git a/drivers/char/xilinx_hwicap/buffer_icap.c b/drivers/char/xilinx_hwicap/buffer_icap.c index 05d897764f02..53c3882e4981 100644 --- a/drivers/char/xilinx_hwicap/buffer_icap.c +++ b/drivers/char/xilinx_hwicap/buffer_icap.c @@ -270,7 +270,7 @@ int buffer_icap_set_configuration(struct hwicap_drvdata *drvdata, u32 *data, int status; s32 buffer_count = 0; s32 num_writes = 0; - bool dirty = 0; + bool dirty = false; u32 i; void __iomem *base_address = drvdata->base_address; @@ -279,7 +279,7 @@ int buffer_icap_set_configuration(struct hwicap_drvdata *drvdata, u32 *data, /* Copy data to bram */ buffer_icap_set_bram(base_address, buffer_count, data[i]); - dirty = 1; + dirty = true; if (buffer_count < XHI_MAX_BUFFER_INTS - 1) { buffer_count++; @@ -299,7 +299,7 @@ int buffer_icap_set_configuration(struct hwicap_drvdata *drvdata, u32 *data, buffer_count = 0; num_writes++; - dirty = 0; + dirty = false; } /* Write unwritten data to ICAP */ diff --git a/drivers/char/xillybus/Kconfig b/drivers/char/xillybus/Kconfig index b53bdf12da0d..b302684d86c1 100644 --- a/drivers/char/xillybus/Kconfig +++ b/drivers/char/xillybus/Kconfig @@ -24,7 +24,7 @@ config XILLYBUS_PCIE config XILLYBUS_OF tristate "Xillybus over Device Tree" - depends on OF_ADDRESS && OF_IRQ + depends on OF_ADDRESS && OF_IRQ && HAS_DMA help Set to M if you want Xillybus to find its resources from the Open Firmware Flattened Device Tree. If the target is an embedded |