diff options
43 files changed, 984 insertions, 518 deletions
diff --git a/Documentation/devicetree/bindings/misc/at25.txt b/Documentation/devicetree/bindings/misc/at25.txt index ab3c327929d..1d3447165c3 100644 --- a/Documentation/devicetree/bindings/misc/at25.txt +++ b/Documentation/devicetree/bindings/misc/at25.txt @@ -1,21 +1,35 @@ -Atmel AT25 eeprom +EEPROMs (SPI) compatible with Atmel at25. Required properties: - compatible : "atmel,at25". - reg : chip select number - spi-max-frequency : max spi frequency to use +- pagesize : size of the eeprom page +- size : total eeprom size in bytes +- address-width : number of address bits (one of 8, 16, or 24) +Optional properties: +- spi-cpha : SPI shifted clock phase, as per spi-bus bindings. +- spi-cpol : SPI inverse clock polarity, as per spi-bus bindings. +- read-only : this parameter-less property disables writes to the eeprom + +Obsolete legacy properties are can be used in place of "size", "pagesize", +"address-width", and "read-only": - at25,byte-len : total eeprom size in bytes - at25,addr-mode : addr-mode flags, as defined in include/linux/spi/eeprom.h - at25,page-size : size of the eeprom page -Examples: -at25@0 { - compatible = "atmel,at25"; - reg = <0> - spi-max-frequency = <5000000>; +Additional compatible properties are also allowed. + +Example: + at25@0 { + compatible = "atmel,at25", "st,m95256"; + reg = <0> + spi-max-frequency = <5000000>; + spi-cpha; + spi-cpol; - at25,byte-len = <0x8000>; - at25,addr-mode = <2>; - at25,page-size = <64>; -}; + pagesize = <64>; + size = <32768>; + address-width = <16>; + }; diff --git a/Documentation/devicetree/bindings/misc/lis302.txt b/Documentation/devicetree/bindings/misc/lis302.txt new file mode 100644 index 00000000000..6def86f6b05 --- /dev/null +++ b/Documentation/devicetree/bindings/misc/lis302.txt @@ -0,0 +1,112 @@ +LIS302 accelerometer devicetree bindings + +This device is matched via its bus drivers, and has a number of properties +that apply in on the generic device (independent from the bus). + + +Required properties for the SPI bindings: + - compatible: should be set to "st,lis3lv02d_spi" + - reg: the chipselect index + - spi-max-frequency: maximal bus speed, should be set to 1000000 unless + constrained by external circuitry + - interrupts: the interrupt generated by the device + +Required properties for the I2C bindings: + - compatible: should be set to "st,lis3lv02d" + - reg: i2c slave address + - Vdd-supply: The input supply for Vdd + - Vdd_IO-supply: The input supply for Vdd_IO + + +Optional properties for all bus drivers: + + - st,click-single-{x,y,z}: if present, tells the device to issue an + interrupt on single click events on the + x/y/z axis. + - st,click-double-{x,y,z}: if present, tells the device to issue an + interrupt on double click events on the + x/y/z axis. + - st,click-thresh-{x,y,z}: set the x/y/z axis threshold + - st,click-click-time-limit: click time limit, from 0 to 127.5msec + with step of 0.5 msec + - st,click-latency: click latency, from 0 to 255 msec with + step of 1 msec. + - st,click-window: click window, from 0 to 255 msec with + step of 1 msec. + - st,irq{1,2}-disable: disable IRQ 1/2 + - st,irq{1,2}-ff-wu-1: raise IRQ 1/2 on FF_WU_1 condition + - st,irq{1,2}-ff-wu-2: raise IRQ 1/2 on FF_WU_2 condition + - st,irq{1,2}-data-ready: raise IRQ 1/2 on data ready contition + - st,irq{1,2}-click: raise IRQ 1/2 on click condition + - st,irq-open-drain: consider IRQ lines open-drain + - st,irq-active-low: make IRQ lines active low + - st,wu-duration-1: duration register for Free-Fall/Wake-Up + interrupt 1 + - st,wu-duration-2: duration register for Free-Fall/Wake-Up + interrupt 2 + - st,wakeup-{x,y,z}-{lo,hi}: set wakeup condition on x/y/z axis for + upper/lower limit + - st,highpass-cutoff-hz=: 1, 2, 4 or 8 for 1Hz, 2Hz, 4Hz or 8Hz of + highpass cut-off frequency + - st,hipass{1,2}-disable: disable highpass 1/2. + - st,default-rate=: set the default rate + - st,axis-{x,y,z}=: set the axis to map to the three coordinates + - st,{min,max}-limit-{x,y,z} set the min/max limits for x/y/z axis + (used by self-test) + + +Example for a SPI device node: + + lis302@0 { + compatible = "st,lis302dl-spi"; + reg = <0>; + spi-max-frequency = <1000000>; + interrupt-parent = <&gpio>; + interrupts = <104 0>; + + st,click-single-x; + st,click-single-y; + st,click-single-z; + st,click-thresh-x = <10>; + st,click-thresh-y = <10>; + st,click-thresh-z = <10>; + st,irq1-click; + st,irq2-click; + st,wakeup-x-lo; + st,wakeup-x-hi; + st,wakeup-y-lo; + st,wakeup-y-hi; + st,wakeup-z-lo; + st,wakeup-z-hi; + }; + +Example for a I2C device node: + + lis331dlh: lis331dlh@18 { + compatible = "st,lis331dlh", "st,lis3lv02d"; + reg = <0x18>; + Vdd-supply = <&lis3_reg>; + Vdd_IO-supply = <&lis3_reg>; + + st,click-single-x; + st,click-single-y; + st,click-single-z; + st,click-thresh-x = <10>; + st,click-thresh-y = <10>; + st,click-thresh-z = <10>; + st,irq1-click; + st,irq2-click; + st,wakeup-x-lo; + st,wakeup-x-hi; + st,wakeup-y-lo; + st,wakeup-y-hi; + st,wakeup-z-lo; + st,wakeup-z-hi; + st,min-limit-x = <120>; + st,min-limit-y = <120>; + st,min-limit-z = <140>; + st,max-limit-x = <550>; + st,max-limit-y = <550>; + st,max-limit-z = <750>; + }; + diff --git a/Documentation/devicetree/bindings/w1/w1-gpio.txt b/Documentation/devicetree/bindings/w1/w1-gpio.txt new file mode 100644 index 00000000000..6e09c35d9f1 --- /dev/null +++ b/Documentation/devicetree/bindings/w1/w1-gpio.txt @@ -0,0 +1,22 @@ +w1-gpio devicetree bindings + +Required properties: + + - compatible: "w1-gpio" + - gpios: one or two GPIO specs: + - the first one is used as data I/O pin + - the second one is optional. If specified, it is used as + enable pin for an external pin pullup. + +Optional properties: + + - linux,open-drain: if specified, the data pin is considered in + open-drain mode. + +Examples: + + onewire@0 { + compatible = "w1-gpio"; + gpios = <&gpio 126 0>, <&gpio 105 0>; + }; + diff --git a/Documentation/misc-devices/lis3lv02d b/Documentation/misc-devices/lis3lv02d index f1a4ec840f8..af815b9ba41 100644 --- a/Documentation/misc-devices/lis3lv02d +++ b/Documentation/misc-devices/lis3lv02d @@ -4,7 +4,8 @@ Kernel driver lis3lv02d Supported chips: * STMicroelectronics LIS3LV02DL, LIS3LV02DQ (12 bits precision) - * STMicroelectronics LIS302DL, LIS3L02DQ, LIS331DL (8 bits) + * STMicroelectronics LIS302DL, LIS3L02DQ, LIS331DL (8 bits) and + LIS331DLH (16 bits) Authors: Yan Burman <burman.yan@gmail.com> diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index ea6f6325f9b..72bedad6bf8 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -418,8 +418,8 @@ config APPLICOM If unsure, say N. config SONYPI - tristate "Sony Vaio Programmable I/O Control Device support (EXPERIMENTAL)" - depends on EXPERIMENTAL && X86 && PCI && INPUT && !64BIT + tristate "Sony Vaio Programmable I/O Control Device support" + depends on X86 && PCI && INPUT && !64BIT ---help--- This driver enables access to the Sony Programmable I/O Control Device which can be found in many (all ?) Sony Vaio laptops. @@ -566,7 +566,7 @@ source "drivers/char/tpm/Kconfig" config TELCLOCK tristate "Telecom clock driver for ATCA SBC" - depends on EXPERIMENTAL && X86 + depends on X86 default n help The telecom clock device is specific to the MPCBL0010 and MPCBL0050 diff --git a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c index 33dc2298af7..3d6c0671e99 100644 --- a/drivers/char/mmtimer.c +++ b/drivers/char/mmtimer.c @@ -826,7 +826,7 @@ static int __init mmtimer_init(void) /* Allocate list of node ptrs to mmtimer_t's */ timers = kzalloc(sizeof(struct mmtimer_node)*maxn, GFP_KERNEL); - if (timers == NULL) { + if (!timers) { printk(KERN_ERR "%s: failed to allocate memory for device\n", MMTIMER_NAME); goto out3; @@ -848,7 +848,6 @@ static int __init mmtimer_init(void) return 0; out3: - kfree(timers); misc_deregister(&mmtimer_miscdev); out2: free_irq(SGI_MMTIMER_VECTOR, NULL); diff --git a/drivers/char/nwbutton.c b/drivers/char/nwbutton.c index 04a480f86c6..cfdfe493c6a 100644 --- a/drivers/char/nwbutton.c +++ b/drivers/char/nwbutton.c @@ -93,9 +93,9 @@ int button_del_callback (void (*callback) (void)) button_callback_list [lp].count = 0; callback_count--; return 0; - }; + } lp--; - }; + } return -EINVAL; } diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 0a484b4a1b0..a6b8ddea222 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -891,6 +891,14 @@ static void rx_ready_async(MGSLPC_INFO *info, int tcd, struct tty_struct *tty) int work = 0; struct mgsl_icount *icount = &info->icount; + if (!tty) { + /* tty is not available anymore */ + issue_command(info, CHA, CMD_RXRESET); + if (debug_level >= DEBUG_LEVEL_ISR) + printk("%s(%d):rx_ready_async(tty=NULL)\n",__FILE__,__LINE__); + return; + } + if (tcd) { /* early termination, get FIFO count from RBCL register */ fifo_count = (unsigned char)(read_reg(info, CHA+RBCL) & 0x1f); @@ -980,7 +988,7 @@ static void tx_done(MGSLPC_INFO *info, struct tty_struct *tty) else #endif { - if (tty->stopped || tty->hw_stopped) { + if (tty && (tty->stopped || tty->hw_stopped)) { tx_stop(info); return; } @@ -1000,7 +1008,7 @@ static void tx_ready(MGSLPC_INFO *info, struct tty_struct *tty) if (!info->tx_active) return; } else { - if (tty->stopped || tty->hw_stopped) { + if (tty && (tty->stopped || tty->hw_stopped)) { tx_stop(info); return; } @@ -1050,13 +1058,12 @@ static void cts_change(MGSLPC_INFO *info, struct tty_struct *tty) wake_up_interruptible(&info->status_event_wait_q); wake_up_interruptible(&info->event_wait_q); - if (info->port.flags & ASYNC_CTS_FLOW) { + if (tty && (info->port.flags & ASYNC_CTS_FLOW)) { if (tty->hw_stopped) { if (info->serial_signals & SerialSignal_CTS) { if (debug_level >= DEBUG_LEVEL_ISR) printk("CTS tx start..."); - if (tty) - tty->hw_stopped = 0; + tty->hw_stopped = 0; tx_start(info, tty); info->pending_bh |= BH_TRANSMIT; return; @@ -1065,8 +1072,7 @@ static void cts_change(MGSLPC_INFO *info, struct tty_struct *tty) if (!(info->serial_signals & SerialSignal_CTS)) { if (debug_level >= DEBUG_LEVEL_ISR) printk("CTS tx stop..."); - if (tty) - tty->hw_stopped = 1; + tty->hw_stopped = 1; tx_stop(info); } } diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c index 3fcf80ff12f..d0d824ebf2c 100644 --- a/drivers/char/ppdev.c +++ b/drivers/char/ppdev.c @@ -783,7 +783,8 @@ static int __init ppdev_init (void) err = PTR_ERR(ppdev_class); goto out_chrdev; } - if (parport_register_driver(&pp_driver)) { + err = parport_register_driver(&pp_driver); + if (err < 0) { printk (KERN_WARNING CHRDEV ": unable to register with parport\n"); goto out_class; } diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index af9437488b6..91470fdbab2 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -411,7 +411,7 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) case RTC_IRQP_READ: case RTC_IRQP_SET: return -EINVAL; - }; + } } #endif diff --git a/drivers/char/tlclk.c b/drivers/char/tlclk.c index ce29e7cce52..e95e0ab0bd8 100644 --- a/drivers/char/tlclk.c +++ b/drivers/char/tlclk.c @@ -784,8 +784,10 @@ static int __init tlclk_init(void) } tlclk_major = ret; alarm_events = kzalloc( sizeof(struct tlclk_alarms), GFP_KERNEL); - if (!alarm_events) + if (!alarm_events) { + ret = -ENOMEM; goto out1; + } /* Read telecom clock IRQ number (Set by BIOS) */ if (!request_region(TLCLK_BASE, 8, "telco_clock")) { diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index cdf2f5451c7..060a672ebb7 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1941,7 +1941,17 @@ static int __init init(void) INIT_LIST_HEAD(&pdrvdata.consoles); INIT_LIST_HEAD(&pdrvdata.portdevs); - return register_virtio_driver(&virtio_console); + err = register_virtio_driver(&virtio_console); + if (err < 0) { + pr_err("Error %d registering virtio driver\n", err); + goto free; + } + return 0; +free: + if (pdrvdata.debugfs_dir) + debugfs_remove_recursive(pdrvdata.debugfs_dir); + class_destroy(pdrvdata.class); + return err; } static void __exit fini(void) diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 98a442da892..99c73352c43 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -105,7 +105,7 @@ config ATMEL_TCB_CLKSRC_BLOCK config IBM_ASM tristate "Device driver for IBM RSA service processor" - depends on X86 && PCI && INPUT && EXPERIMENTAL + depends on X86 && PCI && INPUT ---help--- This option enables device driver support for in-band access to the IBM RSA (Condor) service processor in eServer xSeries systems. @@ -162,8 +162,8 @@ config SGI_IOC4 Otherwise say N. config TIFM_CORE - tristate "TI Flash Media interface support (EXPERIMENTAL)" - depends on EXPERIMENTAL && PCI + tristate "TI Flash Media interface support" + depends on PCI help If you want support for Texas Instruments(R) Flash Media adapters you should select this option and then also choose an appropriate @@ -178,8 +178,8 @@ config TIFM_CORE be called tifm_core. config TIFM_7XX1 - tristate "TI Flash Media PCI74xx/PCI76xx host adapter support (EXPERIMENTAL)" - depends on PCI && TIFM_CORE && EXPERIMENTAL + tristate "TI Flash Media PCI74xx/PCI76xx host adapter support" + depends on PCI && TIFM_CORE default TIFM_CORE help This option enables support for Texas Instruments(R) PCI74xx and @@ -192,7 +192,7 @@ config TIFM_7XX1 config ICS932S401 tristate "Integrated Circuits ICS932S401" - depends on I2C && EXPERIMENTAL + depends on I2C help If you say yes here you get support for the Integrated Circuits ICS932S401 clock control chips. @@ -398,7 +398,7 @@ config EP93XX_PWM config DS1682 tristate "Dallas DS1682 Total Elapsed Time Recorder with Alarm" - depends on I2C && EXPERIMENTAL + depends on I2C help If you say yes here you get support for Dallas Semiconductor DS1682 Total Elapsed Time Recorder. diff --git a/drivers/misc/bmp085-i2c.c b/drivers/misc/bmp085-i2c.c index 9943971c13e..a4f33c995ea 100644 --- a/drivers/misc/bmp085-i2c.c +++ b/drivers/misc/bmp085-i2c.c @@ -57,12 +57,6 @@ static int bmp085_i2c_remove(struct i2c_client *client) return bmp085_remove(&client->dev); } -static const struct of_device_id bmp085_of_match[] = { - { .compatible = "bosch,bmp085", }, - { }, -}; -MODULE_DEVICE_TABLE(of, bmp085_of_match); - static const struct i2c_device_id bmp085_id[] = { { BMP085_NAME, 0 }, { "bmp180", 0 }, @@ -74,7 +68,6 @@ static struct i2c_driver bmp085_i2c_driver = { .driver = { .owner = THIS_MODULE, .name = BMP085_NAME, - .of_match_table = bmp085_of_match }, .id_table = bmp085_id, .probe = bmp085_i2c_probe, diff --git a/drivers/misc/bmp085-spi.c b/drivers/misc/bmp085-spi.c index 78aaff9b523..5e982af9973 100644 --- a/drivers/misc/bmp085-spi.c +++ b/drivers/misc/bmp085-spi.c @@ -73,19 +73,8 @@ static struct spi_driver bmp085_spi_driver = { .remove = __devexit_p(bmp085_spi_remove) }; -static int __init bmp085_spi_init(void) -{ - return spi_register_driver(&bmp085_spi_driver); -} - -static void __exit bmp085_spi_exit(void) -{ - spi_unregister_driver(&bmp085_spi_driver); -} +module_spi_driver(bmp085_spi_driver); MODULE_AUTHOR("Eric Andersson <eric.andersson@unixphere.com>"); MODULE_DESCRIPTION("BMP085 SPI bus driver"); MODULE_LICENSE("GPL"); - -module_init(bmp085_spi_init); -module_exit(bmp085_spi_exit); diff --git a/drivers/misc/c2port/Kconfig b/drivers/misc/c2port/Kconfig index 33ee834e1b8..0dd690e61d3 100644 --- a/drivers/misc/c2port/Kconfig +++ b/drivers/misc/c2port/Kconfig @@ -3,8 +3,7 @@ # menuconfig C2PORT - tristate "Silicon Labs C2 port support (EXPERIMENTAL)" - depends on EXPERIMENTAL + tristate "Silicon Labs C2 port support" default n help This option enables support for Silicon Labs C2 port used to @@ -22,7 +21,7 @@ menuconfig C2PORT if C2PORT config C2PORT_DURAMAR_2150 - tristate "C2 port support for Eurotech's Duramar 2150 (EXPERIMENTAL)" + tristate "C2 port support for Eurotech's Duramar 2150" depends on X86 default n help diff --git a/drivers/misc/carma/carma-fpga-program.c b/drivers/misc/carma/carma-fpga-program.c index a2d25e4857e..eaddfe9db14 100644 --- a/drivers/misc/carma/carma-fpga-program.c +++ b/drivers/misc/carma/carma-fpga-program.c @@ -978,7 +978,6 @@ static int fpga_of_probe(struct platform_device *op) dev_set_drvdata(priv->dev, priv); dma_cap_zero(mask); dma_cap_set(DMA_MEMCPY, mask); - dma_cap_set(DMA_INTERRUPT, mask); dma_cap_set(DMA_SLAVE, mask); dma_cap_set(DMA_SG, mask); diff --git a/drivers/misc/carma/carma-fpga.c b/drivers/misc/carma/carma-fpga.c index 8c279da0741..0c43297ed9a 100644 --- a/drivers/misc/carma/carma-fpga.c +++ b/drivers/misc/carma/carma-fpga.c @@ -666,7 +666,7 @@ static int data_submit_dma(struct fpga_device *priv, struct data_buf *buf) src = SYS_FPGA_BLOCK; tx = chan->device->device_prep_dma_memcpy(chan, dst, src, REG_BLOCK_SIZE, - DMA_PREP_INTERRUPT); + 0); if (!tx) { dev_err(priv->dev, "unable to prep SYS-FPGA DMA\n"); return -ENOMEM; diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig index 701edf65897..c9e695ea7c9 100644 --- a/drivers/misc/eeprom/Kconfig +++ b/drivers/misc/eeprom/Kconfig @@ -50,7 +50,7 @@ config EEPROM_LEGACY config EEPROM_MAX6875 tristate "Maxim MAX6874/5 power supply supervisor" - depends on I2C && EXPERIMENTAL + depends on I2C help If you say yes here you get read-only support for the user EEPROM of the Maxim MAX6874/5 EEPROM-programmable, quad power-supply diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c index 25003d6ceb5..4ed93dd5411 100644 --- a/drivers/misc/eeprom/at25.c +++ b/drivers/misc/eeprom/at25.c @@ -302,6 +302,61 @@ static ssize_t at25_mem_write(struct memory_accessor *mem, const char *buf, /*-------------------------------------------------------------------------*/ +static int at25_np_to_chip(struct device *dev, + struct device_node *np, + struct spi_eeprom *chip) +{ + u32 val; + + memset(chip, 0, sizeof(*chip)); + strncpy(chip->name, np->name, sizeof(chip->name)); + + if (of_property_read_u32(np, "size", &val) == 0 || + of_property_read_u32(np, "at25,byte-len", &val) == 0) { + chip->byte_len = val; + } else { + dev_err(dev, "Error: missing \"size\" property\n"); + return -ENODEV; + } + + if (of_property_read_u32(np, "pagesize", &val) == 0 || + of_property_read_u32(np, "at25,page-size", &val) == 0) { + chip->page_size = (u16)val; + } else { + dev_err(dev, "Error: missing \"pagesize\" property\n"); + return -ENODEV; + } + + if (of_property_read_u32(np, "at25,addr-mode", &val) == 0) { + chip->flags = (u16)val; + } else { + if (of_property_read_u32(np, "address-width", &val)) { + dev_err(dev, + "Error: missing \"address-width\" property\n"); + return -ENODEV; + } + switch (val) { + case 8: + chip->flags |= EE_ADDR1; + break; + case 16: + chip->flags |= EE_ADDR2; + break; + case 24: + chip->flags |= EE_ADDR3; + break; + default: + dev_err(dev, + "Error: bad \"address-width\" property: %u\n", + val); + return -ENODEV; + } + if (of_find_property(np, "read-only", NULL)) + chip->flags |= EE_READONLY; + } + return 0; +} + static int at25_probe(struct spi_device *spi) { struct at25_data *at25 = NULL; @@ -314,33 +369,11 @@ static int at25_probe(struct spi_device *spi) /* Chip description */ if (!spi->dev.platform_data) { if (np) { - u32 val; - - memset(&chip, 0, sizeof(chip)); - strncpy(chip.name, np->name, 10); - - err = of_property_read_u32(np, "at25,byte-len", &val); - if (err) { - dev_dbg(&spi->dev, "invalid chip dt description\n"); - goto fail; - } - chip.byte_len = val; - - err = of_property_read_u32(np, "at25,addr-mode", &val); - if (err) { - dev_dbg(&spi->dev, "invalid chip dt description\n"); - goto fail; - } - chip.flags = (u16)val; - - err = of_property_read_u32(np, "at25,page-size", &val); - if (err) { - dev_dbg(&spi->dev, "invalid chip dt description\n"); + err = at25_np_to_chip(&spi->dev, np, &chip); + if (err) goto fail; - } - chip.page_size = (u16)val; } else { - dev_dbg(&spi->dev, "no chip description\n"); + dev_err(&spi->dev, "Error: no chip description\n"); err = -ENODEV; goto fail; } diff --git a/drivers/misc/hpilo.c b/drivers/misc/hpilo.c index 6df0da4085e..12ccdf94e4f 100644 --- a/drivers/misc/hpilo.c +++ b/drivers/misc/hpilo.c @@ -736,7 +736,14 @@ static void ilo_remove(struct pci_dev *pdev) free_irq(pdev->irq, ilo_hw); ilo_unmap_device(pdev, ilo_hw); pci_release_regions(pdev); - pci_disable_device(pdev); + /* + * pci_disable_device(pdev) used to be here. But this PCI device has + * two functions with interrupt lines connected to a single pin. The + * other one is a USB host controller. So when we disable the PIN here + * e.g. by rmmod hpilo, the controller stops working. It is because + * the interrupt link is disabled in ACPI since it is not refcounted + * yet. See acpi_pci_link_free_irq called from acpi_pci_irq_disable. + */ kfree(ilo_hw); ilo_hwdev[(minor / max_ccb)] = 0; } @@ -826,7 +833,7 @@ unmap: free_regions: pci_release_regions(pdev); disable: - pci_disable_device(pdev); +/* pci_disable_device(pdev); see comment in ilo_remove */ free: kfree(ilo_hw); out: diff --git a/drivers/misc/lis3lv02d/lis3lv02d.c b/drivers/misc/lis3lv02d/lis3lv02d.c index a981e2a42f9..4a87e5c0a32 100644 --- a/drivers/misc/lis3lv02d/lis3lv02d.c +++ b/drivers/misc/lis3lv02d/lis3lv02d.c @@ -39,6 +39,7 @@ #include <linux/miscdevice.h> #include <linux/pm_runtime.h> #include <linux/atomic.h> +#include <linux/of_device.h> #include "lis3lv02d.h" #define DRIVER_NAME "lis3lv02d" @@ -80,6 +81,15 @@ #define LIS3_SENSITIVITY_12B ((LIS3_ACCURACY * 1000) / 1024) #define LIS3_SENSITIVITY_8B (18 * LIS3_ACCURACY) +/* + * LIS331DLH spec says 1LSBs corresponds 4G/4096 -> 1LSB is 1000/1024 mG. + * Below macros defines sensitivity values for +/-2G. Dataout bits for + * +/-2G range is 12 bits so 4 bits adjustment must be done to get 12bit + * data from 16bit value. Currently this driver supports only 2G range. + */ +#define LIS3DLH_SENSITIVITY_2G ((LIS3_ACCURACY * 1000) / 1024) +#define SHIFT_ADJ_2G 4 + #define LIS3_DEFAULT_FUZZ_12B 3 #define LIS3_DEFAULT_FLAT_12B 3 #define LIS3_DEFAULT_FUZZ_8B 1 @@ -135,6 +145,19 @@ static s16 lis3lv02d_read_12(struct lis3lv02d *lis3, int reg) return (s16)((hi << 8) | lo); } +/* 12bits for 2G range, 13 bits for 4G range and 14 bits for 8G range */ +static s16 lis331dlh_read_data(struct lis3lv02d *lis3, int reg) +{ + u8 lo, hi; + int v; + + lis3->read(lis3, reg - 1, &lo); + lis3->read(lis3, reg, &hi); + v = (int) ((hi << 8) | lo); + + return (s16) v >> lis3->shift_adj; +} + /** * lis3lv02d_get_axis - For the given axis, give the value converted * @axis: 1,2,3 - can also be negative @@ -195,6 +218,7 @@ static void lis3lv02d_get_xyz(struct lis3lv02d *lis3, int *x, int *y, int *z) static int lis3_12_rates[4] = {40, 160, 640, 2560}; static int lis3_8_rates[2] = {100, 400}; static int lis3_3dc_rates[16] = {0, 1, 10, 25, 50, 100, 200, 400, 1600, 5000}; +static int lis3_3dlh_rates[4] = {50, 100, 400, 1000}; /* ODR is Output Data Rate */ static int lis3lv02d_get_odr(struct lis3lv02d *lis3) @@ -267,7 +291,7 @@ static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3]) (LIS3_IRQ1_DATA_READY | LIS3_IRQ2_DATA_READY)); } - if (lis3->whoami == WAI_3DC) { + if ((lis3->whoami == WAI_3DC) || (lis3->whoami == WAI_3DLH)) { ctlreg = CTRL_REG4; selftest = CTRL4_ST0; } else { @@ -398,9 +422,17 @@ int lis3lv02d_poweron(struct lis3lv02d *lis3) lis3->read(lis3, CTRL_REG2, ®); if (lis3->whoami == WAI_12B) reg |= CTRL2_BDU | CTRL2_BOOT; + else if (lis3->whoami == WAI_3DLH) + reg |= CTRL2_BOOT_3DLH; else reg |= CTRL2_BOOT_8B; lis3->write(lis3, CTRL_REG2, reg); + + if (lis3->whoami == WAI_3DLH) { + lis3->read(lis3, CTRL_REG4, ®); + reg |= CTRL4_BDU; + lis3->write(lis3, CTRL_REG4, reg); + } } err = lis3lv02d_get_pwron_wait(lis3); @@ -912,6 +944,154 @@ static void lis3lv02d_8b_configure(struct lis3lv02d *lis3, } } +#ifdef CONFIG_OF +int lis3lv02d_init_dt(struct lis3lv02d *lis3) +{ + struct lis3lv02d_platform_data *pdata; + struct device_node *np = lis3->of_node; + u32 val; + + if (!lis3->of_node) + return 0; + + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + if (of_get_property(np, "st,click-single-x", NULL)) + pdata->click_flags |= LIS3_CLICK_SINGLE_X; + if (of_get_property(np, "st,click-double-x", NULL)) + pdata->click_flags |= LIS3_CLICK_DOUBLE_X; + + if (of_get_property(np, "st,click-single-y", NULL)) + pdata->click_flags |= LIS3_CLICK_SINGLE_Y; + if (of_get_property(np, "st,click-double-y", NULL)) + pdata->click_flags |= LIS3_CLICK_DOUBLE_Y; + + if (of_get_property(np, "st,click-single-z", NULL)) + pdata->click_flags |= LIS3_CLICK_SINGLE_Z; + if (of_get_property(np, "st,click-double-z", NULL)) + pdata->click_flags |= LIS3_CLICK_DOUBLE_Z; + + if (!of_property_read_u32(np, "st,click-threshold-x", &val)) + pdata->click_thresh_x = val; + if (!of_property_read_u32(np, "st,click-threshold-y", &val)) + pdata->click_thresh_y = val; + if (!of_property_read_u32(np, "st,click-threshold-z", &val)) + pdata->click_thresh_z = val; + + if (!of_property_read_u32(np, "st,click-time-limit", &val)) + pdata->click_time_limit = val; + if (!of_property_read_u32(np, "st,click-latency", &val)) + pdata->click_latency = val; + if (!of_property_read_u32(np, "st,click-window", &val)) + pdata->click_window = val; + + if (of_get_property(np, "st,irq1-disable", NULL)) + pdata->irq_cfg |= LIS3_IRQ1_DISABLE; + if (of_get_property(np, "st,irq1-ff-wu-1", NULL)) + pdata->irq_cfg |= LIS3_IRQ1_FF_WU_1; + if (of_get_property(np, "st,irq1-ff-wu-2", NULL)) + pdata->irq_cfg |= LIS3_IRQ1_FF_WU_2; + if (of_get_property(np, "st,irq1-data-ready", NULL)) + pdata->irq_cfg |= LIS3_IRQ1_DATA_READY; + if (of_get_property(np, "st,irq1-click", NULL)) + pdata->irq_cfg |= LIS3_IRQ1_CLICK; + + if (of_get_property(np, "st,irq2-disable", NULL)) + pdata->irq_cfg |= LIS3_IRQ2_DISABLE; + if (of_get_property(np, "st,irq2-ff-wu-1", NULL)) + pdata->irq_cfg |= LIS3_IRQ2_FF_WU_1; + if (of_get_property(np, "st,irq2-ff-wu-2", NULL)) + pdata->irq_cfg |= LIS3_IRQ2_FF_WU_2; + if (of_get_property(np, "st,irq2-data-ready", NULL)) + pdata->irq_cfg |= LIS3_IRQ2_DATA_READY; + if (of_get_property(np, "st,irq2-click", NULL)) + pdata->irq_cfg |= LIS3_IRQ2_CLICK; + + if (of_get_property(np, "st,irq-open-drain", NULL)) + pdata->irq_cfg |= LIS3_IRQ_OPEN_DRAIN; + if (of_get_property(np, "st,irq-active-low", NULL)) + pdata->irq_cfg |= LIS3_IRQ_ACTIVE_LOW; + + if (!of_property_read_u32(np, "st,wu-duration-1", &val)) + pdata->duration1 = val; + if (!of_property_read_u32(np, "st,wu-duration-2", &val)) + pdata->duration2 = val; + + if (of_get_property(np, "st,wakeup-x-lo", NULL)) + pdata->wakeup_flags |= LIS3_WAKEUP_X_LO; + if (of_get_property(np, "st,wakeup-x-hi", NULL)) + pdata->wakeup_flags |= LIS3_WAKEUP_X_HI; + if (of_get_property(np, "st,wakeup-y-lo", NULL)) + pdata->wakeup_flags |= LIS3_WAKEUP_Y_LO; + if (of_get_property(np, "st,wakeup-y-hi", NULL)) + pdata->wakeup_flags |= LIS3_WAKEUP_Y_HI; + if (of_get_property(np, "st,wakeup-z-lo", NULL)) + pdata->wakeup_flags |= LIS3_WAKEUP_Z_LO; + if (of_get_property(np, "st,wakeup-z-hi", NULL)) + pdata->wakeup_flags |= LIS3_WAKEUP_Z_HI; + + if (!of_property_read_u32(np, "st,highpass-cutoff-hz", &val)) { + switch (val) { + case 1: + pdata->hipass_ctrl = LIS3_HIPASS_CUTFF_1HZ; + break; + case 2: + pdata->hipass_ctrl = LIS3_HIPASS_CUTFF_2HZ; + break; + case 4: + pdata->hipass_ctrl = LIS3_HIPASS_CUTFF_4HZ; + break; + case 8: + pdata->hipass_ctrl = LIS3_HIPASS_CUTFF_8HZ; + break; + } + } + + if (of_get_property(np, "st,hipass1-disable", NULL)) + pdata->hipass_ctrl |= LIS3_HIPASS1_DISABLE; + if (of_get_property(np, "st,hipass2-disable", NULL)) + pdata->hipass_ctrl |= LIS3_HIPASS2_DISABLE; + + if (of_get_property(np, "st,axis-x", &val)) + pdata->axis_x = val; + if (of_get_property(np, "st,axis-y", &val)) + pdata->axis_y = val; + if (of_get_property(np, "st,axis-z", &val)) + pdata->axis_z = val; + + if (of_get_property(np, "st,default-rate", NULL)) + pdata->default_rate = val; + + if (of_get_property(np, "st,min-limit-x", &val)) + pdata->st_min_limits[0] = val; + if (of_get_property(np, "st,min-limit-y", &val)) + pdata->st_min_limits[1] = val; + if (of_get_property(np, "st,min-limit-z", &val)) + pdata->st_min_limits[2] = val; + + if (of_get_property(np, "st,max-limit-x", &val)) + pdata->st_max_limits[0] = val; + if (of_get_property(np, "st,max-limit-y", &val)) + pdata->st_max_limits[1] = val; + if (of_get_property(np, "st,max-limit-z", &val)) + pdata->st_max_limits[2] = val; + + + lis3->pdata = pdata; + + return 0; +} + +#else +int lis3lv02d_init_dt(struct lis3lv02d *lis3) +{ + return 0; +} +#endif +EXPORT_SYMBOL_GPL(lis3lv02d_init_dt); + /* * Initialise the accelerometer and the various subsystems. * Should be rather independent of the bus system. @@ -956,6 +1136,16 @@ int lis3lv02d_init_device(struct lis3lv02d *lis3) lis3->odr_mask = CTRL1_ODR0|CTRL1_ODR1|CTRL1_ODR2|CTRL1_ODR3; lis3->scale = LIS3_SENSITIVITY_8B; break; + case WAI_3DLH: + pr_info("16 bits lis331dlh sensor found\n"); + lis3->read_data = lis331dlh_read_data; + lis3->mdps_max_val = 2048; /* 12 bits for 2G */ + lis3->shift_adj = SHIFT_ADJ_2G; + lis3->pwron_delay = LIS3_PWRON_DELAY_WAI_8B; + lis3->odrs = lis3_3dlh_rates; + lis3->odr_mask = CTRL1_DR0 | CTRL1_DR1; + lis3->scale = LIS3DLH_SENSITIVITY_2G; + break; default: pr_err("unknown sensor type 0x%X\n", lis3->whoami); return -EINVAL; diff --git a/drivers/misc/lis3lv02d/lis3lv02d.h b/drivers/misc/lis3lv02d/lis3lv02d.h index 2b1482ad3f1..c439c827eea 100644 --- a/drivers/misc/lis3lv02d/lis3lv02d.h +++ b/drivers/misc/lis3lv02d/lis3lv02d.h @@ -26,12 +26,12 @@ /* * This driver tries to support the "digital" accelerometer chips from * STMicroelectronics such as LIS3LV02DL, LIS302DL, LIS3L02DQ, LIS331DL, - * LIS35DE, or LIS202DL. They are very similar in terms of programming, with - * almost the same registers. In addition to differing on physical properties, - * they differ on the number of axes (2/3), precision (8/12 bits), and special - * features (freefall detection, click...). Unfortunately, not all the - * differences can be probed via a register. - * They can be connected either via I²C or SPI. + * LIS331DLH, LIS35DE, or LIS202DL. They are very similar in terms of + * programming, with almost the same registers. In addition to differing + * on physical properties, they differ on the number of axes (2/3), + * precision (8/12 bits), and special features (freefall detection, + * click...). Unfortunately, not all the differences can be probed via + * a register. They can be connected either via I²C or SPI. */ #include <linux/lis3lv02d.h> @@ -96,12 +96,22 @@ enum lis3lv02d_reg { }; enum lis3_who_am_i { + WAI_3DLH = 0x32, /* 16 bits: LIS331DLH */ WAI_3DC = 0x33, /* 8 bits: LIS3DC, HP3DC */ WAI_12B = 0x3A, /* 12 bits: LIS3LV02D[LQ]... */ WAI_8B = 0x3B, /* 8 bits: LIS[23]02D[LQ]... */ WAI_6B = 0x52, /* 6 bits: LIS331DLF - not supported */ }; +enum lis3_type { + LIS3LV02D, + LIS3DC, + HP3DC, + LIS2302D, + LIS331DLF, + LIS331DLH, +}; + enum lis3lv02d_ctrl1_12b { CTRL1_Xen = 0x01, CTRL1_Yen = 0x02, @@ -129,6 +139,27 @@ enum lis3lv02d_ctrl1_3dc { CTRL1_ODR3 = 0x80, }; +enum lis331dlh_ctrl1 { + CTRL1_DR0 = 0x08, + CTRL1_DR1 = 0x10, + CTRL1_PM0 = 0x20, + CTRL1_PM1 = 0x40, + CTRL1_PM2 = 0x80, +}; + +enum lis331dlh_ctrl2 { + CTRL2_HPEN1 = 0x04, + CTRL2_HPEN2 = 0x08, + CTRL2_FDS_3DLH = 0x10, + CTRL2_BOOT_3DLH = 0x80, +}; + +enum lis331dlh_ctrl4 { + CTRL4_STSIGN = 0x08, + CTRL4_BLE = 0x40, + CTRL4_BDU = 0x80, +}; + enum lis3lv02d_ctrl2 { CTRL2_DAS = 0x01, CTRL2_SIM = 0x02, @@ -279,9 +310,14 @@ struct lis3lv02d { int data_ready_count[2]; atomic_t wake_thread; unsigned char irq_cfg; + unsigned int shift_adj; struct lis3lv02d_platform_data *pdata; /* for passing board config */ struct mutex mutex; /* Serialize poll and selftest */ + +#ifdef CONFIG_OF + struct device_node *of_node; +#endif }; int lis3lv02d_init_device(struct lis3lv02d *lis3); @@ -290,5 +326,6 @@ void lis3lv02d_joystick_disable(struct lis3lv02d *lis3); void lis3lv02d_poweroff(struct lis3lv02d *lis3); int lis3lv02d_poweron(struct lis3lv02d *lis3); int lis3lv02d_remove_fs(struct lis3lv02d *lis3); +int lis3lv02d_init_dt(struct lis3lv02d *lis3); extern struct lis3lv02d lis3_dev; diff --git a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c index e8c0019da97..60ec8689d6e 100644 --- a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c +++ b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c @@ -31,6 +31,10 @@ #include <linux/i2c.h> #include <linux/pm_runtime.h> #include <linux/delay.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/of_device.h> + #include "lis3lv02d.h" #define DRV_NAME "lis3lv02d_i2c" @@ -90,7 +94,11 @@ static int lis3_i2c_init(struct lis3lv02d *lis3) if (ret < 0) return ret; - reg |= CTRL1_PD0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen; + if (lis3->whoami == WAI_3DLH) + reg |= CTRL1_PM0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen; + else + reg |= CTRL1_PD0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen; + return lis3->write(lis3, CTRL_REG1, reg); } @@ -98,12 +106,30 @@ static int lis3_i2c_init(struct lis3lv02d *lis3) static union axis_conversion lis3lv02d_axis_map = { .as_array = { LIS3_DEV_X, LIS3_DEV_Y, LIS3_DEV_Z } }; +#ifdef CONFIG_OF +static struct of_device_id lis3lv02d_i2c_dt_ids[] = { + { .compatible = "st,lis3lv02d" }, + {} +}; +MODULE_DEVICE_TABLE(of, lis3lv02d_i2c_dt_ids); +#endif + static int __devinit lis3lv02d_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { int ret = 0; struct lis3lv02d_platform_data *pdata = client->dev.platform_data; +#ifdef CONFIG_OF + if (of_match_device(lis3lv02d_i2c_dt_ids, &client->dev)) { + lis3_dev.of_node = client->dev.of_node; + ret = lis3lv02d_init_dt(&lis3_dev); + if (ret) + return ret; + pdata = lis3_dev.pdata; + } +#endif + if (pdata) { if ((pdata->driver_features & LIS3_USE_BLOCK_READ) && (i2c_check_functionality(client->adapter, @@ -231,7 +257,8 @@ static int lis3_i2c_runtime_resume(struct device *dev) #endif /* CONFIG_PM_RUNTIME */ static const struct i2c_device_id lis3lv02d_id[] = { - {"lis3lv02d", 0 }, + {"lis3lv02d", LIS3LV02D}, + {"lis331dlh", LIS331DLH}, {} }; @@ -250,6 +277,7 @@ static struct i2c_driver lis3lv02d_i2c_driver = { .name = DRV_NAME, .owner = THIS_MODULE, .pm = &lis3_pm_ops, + .of_match_table = of_match_ptr(lis3lv02d_i2c_dt_ids), }, .probe = lis3lv02d_i2c_probe, .remove = __devexit_p(lis3lv02d_i2c_remove), diff --git a/drivers/misc/lis3lv02d/lis3lv02d_spi.c b/drivers/misc/lis3lv02d/lis3lv02d_spi.c index 80880e984b4..ccb6475fa05 100644 --- a/drivers/misc/lis3lv02d/lis3lv02d_spi.c +++ b/drivers/misc/lis3lv02d/lis3lv02d_spi.c @@ -17,6 +17,9 @@ #include <linux/workqueue.h> #include <linux/spi/spi.h> #include <linux/pm.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/of_device.h> #include "lis3lv02d.h" @@ -58,6 +61,14 @@ static int lis3_spi_init(struct lis3lv02d *lis3) static union axis_conversion lis3lv02d_axis_normal = { .as_array = { 1, 2, 3 } }; +#ifdef CONFIG_OF +static struct of_device_id lis302dl_spi_dt_ids[] = { + { .compatible = "st,lis302dl-spi" }, + {} +}; +MODULE_DEVICE_TABLE(of, lis302dl_spi_dt_ids); +#endif + static int __devinit lis302dl_spi_probe(struct spi_device *spi) { int ret; @@ -75,6 +86,15 @@ static int __devinit lis302dl_spi_probe(struct spi_device *spi) lis3_dev.irq = spi->irq; lis3_dev.ac = lis3lv02d_axis_normal; lis3_dev.pdata = spi->dev.platform_data; + +#ifdef CONFIG_OF + if (of_match_device(lis302dl_spi_dt_ids, &spi->dev)) { + lis3_dev.of_node = spi->dev.of_node; + ret = lis3lv02d_init_dt(&lis3_dev); + if (ret) + return ret; + } +#endif spi_set_drvdata(spi, &lis3_dev); return lis3lv02d_init_device(&lis3_dev); @@ -121,6 +141,7 @@ static struct spi_driver lis302dl_spi_driver = { .name = DRV_NAME, .owner = THIS_MODULE, .pm = &lis3lv02d_spi_pm, + .of_match_table = of_match_ptr(lis302dl_spi_dt_ids), }, .probe = lis302dl_spi_probe, .remove = __devexit_p(lis302dl_spi_remove), diff --git a/drivers/misc/mei/Kconfig b/drivers/misc/mei/Kconfig index 47d78a72db2..5a79ccde2fd 100644 --- a/drivers/misc/mei/Kconfig +++ b/drivers/misc/mei/Kconfig @@ -1,6 +1,6 @@ config INTEL_MEI tristate "Intel Management Engine Interface (Intel MEI)" - depends on X86 && PCI && EXPERIMENTAL && WATCHDOG_CORE + depends on X86 && PCI && WATCHDOG_CORE help The Intel Management Engine (Intel ME) provides Manageability, Security and Media services for system containing Intel chipsets. diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h index 24c4c962819..9700532f02f 100644 --- a/drivers/misc/mei/hw.h +++ b/drivers/misc/mei/hw.h @@ -40,47 +40,48 @@ /* * MEI device IDs */ -#define MEI_DEV_ID_82946GZ 0x2974 /* 82946GZ/GL */ -#define MEI_DEV_ID_82G35 0x2984 /* 82G35 Express */ -#define MEI_DEV_ID_82Q965 0x2994 /* 82Q963/Q965 */ -#define MEI_DEV_ID_82G965 0x29A4 /* 82P965/G965 */ - -#define MEI_DEV_ID_82GM965 0x2A04 /* Mobile PM965/GM965 */ -#define MEI_DEV_ID_82GME965 0x2A14 /* Mobile GME965/GLE960 */ - -#define MEI_DEV_ID_ICH9_82Q35 0x29B4 /* 82Q35 Express */ -#define MEI_DEV_ID_ICH9_82G33 0x29C4 /* 82G33/G31/P35/P31 Express */ -#define MEI_DEV_ID_ICH9_82Q33 0x29D4 /* 82Q33 Express */ -#define MEI_DEV_ID_ICH9_82X38 0x29E4 /* 82X38/X48 Express */ -#define MEI_DEV_ID_ICH9_3200 0x29F4 /* 3200/3210 Server */ - -#define MEI_DEV_ID_ICH9_6 0x28B4 /* Bearlake */ -#define MEI_DEV_ID_ICH9_7 0x28C4 /* Bearlake */ -#define MEI_DEV_ID_ICH9_8 0x28D4 /* Bearlake */ -#define MEI_DEV_ID_ICH9_9 0x28E4 /* Bearlake */ -#define MEI_DEV_ID_ICH9_10 0x28F4 /* Bearlake */ - -#define MEI_DEV_ID_ICH9M_1 0x2A44 /* Cantiga */ -#define MEI_DEV_ID_ICH9M_2 0x2A54 /* Cantiga */ -#define MEI_DEV_ID_ICH9M_3 0x2A64 /* Cantiga */ -#define MEI_DEV_ID_ICH9M_4 0x2A74 /* Cantiga */ - -#define MEI_DEV_ID_ICH10_1 0x2E04 /* Eaglelake */ -#define MEI_DEV_ID_ICH10_2 0x2E14 /* Eaglelake */ -#define MEI_DEV_ID_ICH10_3 0x2E24 /* Eaglelake */ -#define MEI_DEV_ID_ICH10_4 0x2E34 /* Eaglelake */ - -#define MEI_DEV_ID_IBXPK_1 0x3B64 /* Calpella */ -#define MEI_DEV_ID_IBXPK_2 0x3B65 /* Calpella */ - -#define MEI_DEV_ID_CPT_1 0x1C3A /* Cougerpoint */ -#define MEI_DEV_ID_PBG_1 0x1D3A /* PBG */ - -#define MEI_DEV_ID_PPT_1 0x1E3A /* Pantherpoint PPT */ -#define MEI_DEV_ID_PPT_2 0x1CBA /* Pantherpoint PPT */ -#define MEI_DEV_ID_PPT_3 0x1DBA /* Pantherpoint PPT */ - - +#define MEI_DEV_ID_82946GZ 0x2974 /* 82946GZ/GL */ +#define MEI_DEV_ID_82G35 0x2984 /* 82G35 Express */ +#define MEI_DEV_ID_82Q965 0x2994 /* 82Q963/Q965 */ +#define MEI_DEV_ID_82G965 0x29A4 /* 82P965/G965 */ + +#define MEI_DEV_ID_82GM965 0x2A04 /* Mobile PM965/GM965 */ +#define MEI_DEV_ID_82GME965 0x2A14 /* Mobile GME965/GLE960 */ + +#define MEI_DEV_ID_ICH9_82Q35 0x29B4 /* 82Q35 Express */ +#define MEI_DEV_ID_ICH9_82G33 0x29C4 /* 82G33/G31/P35/P31 Express */ +#define MEI_DEV_ID_ICH9_82Q33 0x29D4 /* 82Q33 Express */ +#define MEI_DEV_ID_ICH9_82X38 0x29E4 /* 82X38/X48 Express */ +#define MEI_DEV_ID_ICH9_3200 0x29F4 /* 3200/3210 Server */ + +#define MEI_DEV_ID_ICH9_6 0x28B4 /* Bearlake */ +#define MEI_DEV_ID_ICH9_7 0x28C4 /* Bearlake */ +#define MEI_DEV_ID_ICH9_8 0x28D4 /* Bearlake */ +#define MEI_DEV_ID_ICH9_9 0x28E4 /* Bearlake */ +#define MEI_DEV_ID_ICH9_10 0x28F4 /* Bearlake */ + +#define MEI_DEV_ID_ICH9M_1 0x2A44 /* Cantiga */ +#define MEI_DEV_ID_ICH9M_2 0x2A54 /* Cantiga */ +#define MEI_DEV_ID_ICH9M_3 0x2A64 /* Cantiga */ +#define MEI_DEV_ID_ICH9M_4 0x2A74 /* Cantiga */ + +#define MEI_DEV_ID_ICH10_1 0x2E04 /* Eaglelake */ +#define MEI_DEV_ID_ICH10_2 0x2E14 /* Eaglelake */ +#define MEI_DEV_ID_ICH10_3 0x2E24 /* Eaglelake */ +#define MEI_DEV_ID_ICH10_4 0x2E34 /* Eaglelake */ + +#define MEI_DEV_ID_IBXPK_1 0x3B64 /* Calpella */ +#define MEI_DEV_ID_IBXPK_2 0x3B65 /* Calpella */ + +#define MEI_DEV_ID_CPT_1 0x1C3A /* Couger Point */ +#define MEI_DEV_ID_PBG_1 0x1D3A /* C600/X79 Patsburg */ + +#define MEI_DEV_ID_PPT_1 0x1E3A /* Panther Point */ +#define MEI_DEV_ID_PPT_2 0x1CBA /* Panther Point */ +#define MEI_DEV_ID_PPT_3 0x1DBA /* Panther Point */ + +#define MEI_DEV_ID_LPT 0x8C3A /* Lynx Point */ +#define MEI_DEV_ID_LPT_LP 0x9C3A /* Lynx Point LP */ /* * MEI HW Section */ diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index e77f86e69fb..98f1430e3e1 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c @@ -24,6 +24,25 @@ #include "interface.h" #include <linux/mei.h> +const char *mei_dev_state_str(int state) +{ +#define MEI_DEV_STATE(state) case MEI_DEV_##state: return #state + switch (state) { + MEI_DEV_STATE(INITIALIZING); + MEI_DEV_STATE(INIT_CLIENTS); + MEI_DEV_STATE(ENABLED); + MEI_DEV_STATE(RESETING); + MEI_DEV_STATE(DISABLED); + MEI_DEV_STATE(RECOVERING_FROM_RESET); + MEI_DEV_STATE(POWER_DOWN); + MEI_DEV_STATE(POWER_UP); + default: + return "unkown"; + } +#undef MEI_DEV_STATE +} + + const uuid_le mei_amthi_guid = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, 0xac, 0xa8, 0x46, 0xe0, 0xff, 0x65, 0x81, 0x4c); @@ -123,7 +142,7 @@ struct mei_device *mei_device_init(struct pci_dev *pdev) mutex_init(&dev->device_lock); init_waitqueue_head(&dev->wait_recvd_msg); init_waitqueue_head(&dev->wait_stop_wd); - dev->mei_state = MEI_INITIALIZING; + dev->dev_state = MEI_DEV_INITIALIZING; dev->iamthif_state = MEI_IAMTHIF_IDLE; dev->wd_interface_reg = false; @@ -182,7 +201,7 @@ int mei_hw_init(struct mei_device *dev) } if (err <= 0 && !dev->recvd_msg) { - dev->mei_state = MEI_DISABLED; + dev->dev_state = MEI_DEV_DISABLED; dev_dbg(&dev->pdev->dev, "wait_event_interruptible_timeout failed" "on wait for ME to turn on ME_RDY.\n"); @@ -192,7 +211,7 @@ int mei_hw_init(struct mei_device *dev) if (!(((dev->host_hw_state & H_RDY) == H_RDY) && ((dev->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA))) { - dev->mei_state = MEI_DISABLED; + dev->dev_state = MEI_DEV_DISABLED; dev_dbg(&dev->pdev->dev, "host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n", dev->host_hw_state, dev->me_hw_state); @@ -258,15 +277,15 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled) struct mei_cl_cb *cb_next = NULL; bool unexpected; - if (dev->mei_state == MEI_RECOVERING_FROM_RESET) { + if (dev->dev_state == MEI_DEV_RECOVERING_FROM_RESET) { dev->need_reset = true; return; } - unexpected = (dev->mei_state != MEI_INITIALIZING && - dev->mei_state != MEI_DISABLED && - dev->mei_state != MEI_POWER_DOWN && - dev->mei_state != MEI_POWER_UP); + unexpected = (dev->dev_state != MEI_DEV_INITIALIZING && + dev->dev_state != MEI_DEV_DISABLED && + dev->dev_state != MEI_DEV_POWER_DOWN && + dev->dev_state != MEI_DEV_POWER_UP); dev->host_hw_state = mei_hcsr_read(dev); @@ -285,10 +304,10 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled) dev->need_reset = false; - if (dev->mei_state != MEI_INITIALIZING) { - if (dev->mei_state != MEI_DISABLED && - dev->mei_state != MEI_POWER_DOWN) - dev->mei_state = MEI_RESETING; + if (dev->dev_state != MEI_DEV_INITIALIZING) { + if (dev->dev_state != MEI_DEV_DISABLED && + dev->dev_state != MEI_DEV_POWER_DOWN) + dev->dev_state = MEI_DEV_RESETING; list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) { @@ -311,7 +330,6 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled) dev->me_clients_num = 0; dev->rd_msg_hdr = 0; - dev->stop = false; dev->wd_pending = false; /* update the state of the registers after reset */ @@ -322,7 +340,8 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled) dev->host_hw_state, dev->me_hw_state); if (unexpected) - dev_warn(&dev->pdev->dev, "unexpected reset.\n"); + dev_warn(&dev->pdev->dev, "unexpected reset: dev_state = %s\n", + mei_dev_state_str(dev->dev_state)); /* Wake up all readings so they can be interrupted */ list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) { @@ -371,7 +390,7 @@ void mei_host_start_message(struct mei_device *dev) if (mei_write_message(dev, mei_hdr, (unsigned char *)host_start_req, mei_hdr->length)) { dev_dbg(&dev->pdev->dev, "write send version message to FW fail.\n"); - dev->mei_state = MEI_RESETING; + dev->dev_state = MEI_DEV_RESETING; mei_reset(dev, 1); } dev->init_clients_state = MEI_START_MESSAGE; @@ -403,7 +422,7 @@ void mei_host_enum_clients_message(struct mei_device *dev) host_enum_req->hbm_cmd = HOST_ENUM_REQ_CMD; if (mei_write_message(dev, mei_hdr, (unsigned char *)host_enum_req, mei_hdr->length)) { - dev->mei_state = MEI_RESETING; + dev->dev_state = MEI_DEV_RESETING; dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n"); mei_reset(dev, 1); } @@ -444,7 +463,7 @@ void mei_allocate_me_clients_storage(struct mei_device *dev) sizeof(struct mei_me_client), GFP_KERNEL); if (!clients) { dev_dbg(&dev->pdev->dev, "memory allocation for ME clients failed.\n"); - dev->mei_state = MEI_RESETING; + dev->dev_state = MEI_DEV_RESETING; mei_reset(dev, 1); return ; } @@ -490,7 +509,7 @@ int mei_host_client_properties(struct mei_device *dev) if (mei_write_message(dev, mei_header, (unsigned char *)host_cli_req, mei_header->length)) { - dev->mei_state = MEI_RESETING; + dev->dev_state = MEI_DEV_RESETING; dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n"); mei_reset(dev, 1); return -EIO; @@ -522,12 +541,12 @@ void mei_cl_init(struct mei_cl *priv, struct mei_device *dev) priv->dev = dev; } -int mei_find_me_client_index(const struct mei_device *dev, uuid_le cuuid) +int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *cuuid) { - int i, res = -1; + int i, res = -ENOENT; for (i = 0; i < dev->me_clients_num; ++i) - if (uuid_le_cmp(cuuid, + if (uuid_le_cmp(*cuuid, dev->me_clients[i].props.protocol_name) == 0) { res = i; break; @@ -538,35 +557,35 @@ int mei_find_me_client_index(const struct mei_device *dev, uuid_le cuuid) /** - * mei_find_me_client_update_filext - searches for ME client guid + * mei_me_cl_update_filext - searches for ME client guid * sets client_id in mei_file_private if found * @dev: the device structure - * @priv: private file structure to set client_id in - * @cguid: searched guid of ME client + * @cl: private file structure to set client_id in + * @cuuid: searched uuid of ME client * @client_id: id of host client to be set in file private structure * * returns ME client index */ -u8 mei_find_me_client_update_filext(struct mei_device *dev, struct mei_cl *priv, - const uuid_le *cguid, u8 client_id) +int mei_me_cl_update_filext(struct mei_device *dev, struct mei_cl *cl, + const uuid_le *cuuid, u8 host_cl_id) { int i; - if (!dev || !priv || !cguid) - return 0; + if (!dev || !cl || !cuuid) + return -EINVAL; /* check for valid client id */ - i = mei_find_me_client_index(dev, *cguid); + i = mei_me_cl_by_uuid(dev, cuuid); if (i >= 0) { - priv->me_client_id = dev->me_clients[i].client_id; - priv->state = MEI_FILE_CONNECTING; - priv->host_client_id = client_id; + cl->me_client_id = dev->me_clients[i].client_id; + cl->state = MEI_FILE_CONNECTING; + cl->host_client_id = host_cl_id; - list_add_tail(&priv->link, &dev->file_list); + list_add_tail(&cl->link, &dev->file_list); return (u8)i; } - return 0; + return -ENOENT; } /** @@ -577,16 +596,16 @@ u8 mei_find_me_client_update_filext(struct mei_device *dev, struct mei_cl *priv, */ void mei_host_init_iamthif(struct mei_device *dev) { - u8 i; + int i; unsigned char *msg_buf; mei_cl_init(&dev->iamthif_cl, dev); dev->iamthif_cl.state = MEI_FILE_DISCONNECTED; /* find ME amthi client */ - i = mei_find_me_client_update_filext(dev, &dev->iamthif_cl, + i = mei_me_cl_update_filext(dev, &dev->iamthif_cl, &mei_amthi_guid, MEI_IAMTHIF_HOST_CLIENT_ID); - if (dev->iamthif_cl.state != MEI_FILE_CONNECTING) { + if (i < 0) { dev_dbg(&dev->pdev->dev, "failed to find iamthif client.\n"); return; } diff --git a/drivers/misc/mei/interface.h b/drivers/misc/mei/interface.h index fb5c7db4723..ec6c785a396 100644 --- a/drivers/misc/mei/interface.h +++ b/drivers/misc/mei/interface.h @@ -23,14 +23,6 @@ #include "mei_dev.h" -#define AMT_WD_DEFAULT_TIMEOUT 120 /* seconds */ -#define AMT_WD_MIN_TIMEOUT 120 /* seconds */ -#define AMT_WD_MAX_TIMEOUT 65535 /* seconds */ - -#define MEI_WATCHDOG_DATA_SIZE 16 -#define MEI_START_WD_DATA_SIZE 20 -#define MEI_WD_PARAMS_SIZE 4 - void mei_read_slots(struct mei_device *dev, unsigned char *buffer, @@ -64,7 +56,7 @@ int mei_flow_ctrl_creds(struct mei_device *dev, struct mei_cl *cl); int mei_wd_send(struct mei_device *dev); -int mei_wd_stop(struct mei_device *dev, bool preserve); +int mei_wd_stop(struct mei_device *dev); int mei_wd_host_init(struct mei_device *dev); /* * mei_watchdog_register - Registering watchdog interface diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index d78c05e693f..3533edde04a 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -221,17 +221,10 @@ static int mei_irq_thread_read_client_message(struct mei_io_list *complete_list, cl->status = 0; list_del(&cb_pos->cb_list); dev_dbg(&dev->pdev->dev, - "completed read host client = %d," - "ME client = %d, " - "data length = %lu\n", + "completed read H cl = %d, ME cl = %d, length = %lu\n", cl->host_client_id, cl->me_client_id, cb_pos->information); - - *(cb_pos->response_buffer.data + - cb_pos->information) = '\0'; - dev_dbg(&dev->pdev->dev, "cb_pos->res_buffer - %s\n", - cb_pos->response_buffer.data); list_add_tail(&cb_pos->cb_list, &complete_list->mei_cb.cb_list); } @@ -633,7 +626,7 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, if (version_res->host_version_supported) { dev->version.major_version = HBM_MAJOR_VERSION; dev->version.minor_version = HBM_MINOR_VERSION; - if (dev->mei_state == MEI_INIT_CLIENTS && + if (dev->dev_state == MEI_DEV_INIT_CLIENTS && dev->init_clients_state == MEI_START_MESSAGE) { dev->init_clients_timer = 0; mei_host_enum_clients_message(dev); @@ -707,7 +700,7 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, dev->me_clients[dev->me_client_presentation_num].props = props_res->client_properties; - if (dev->mei_state == MEI_INIT_CLIENTS && + if (dev->dev_state == MEI_DEV_INIT_CLIENTS && dev->init_clients_state == MEI_CLIENT_PROPERTIES_MESSAGE) { dev->me_client_index++; @@ -734,7 +727,7 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, * Client ID 2 - Reserved for AMTHI */ bitmap_set(dev->host_clients_map, 0, 3); - dev->mei_state = MEI_ENABLED; + dev->dev_state = MEI_DEV_ENABLED; /* if wd initialization fails, initialization the AMTHI client, * otherwise the AMTHI client will be initialized after the WD client connect response @@ -759,7 +752,7 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, case HOST_ENUM_RES_CMD: enum_res = (struct hbm_host_enum_response *) mei_msg; memcpy(dev->me_clients_map, enum_res->valid_addresses, 32); - if (dev->mei_state == MEI_INIT_CLIENTS && + if (dev->dev_state == MEI_DEV_INIT_CLIENTS && dev->init_clients_state == MEI_ENUM_CLIENTS_MESSAGE) { dev->init_clients_timer = 0; dev->me_client_presentation_num = 0; @@ -776,7 +769,7 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, break; case HOST_STOP_RES_CMD: - dev->mei_state = MEI_DISABLED; + dev->dev_state = MEI_DEV_DISABLED; dev_dbg(&dev->pdev->dev, "resetting because of FW stop response.\n"); mei_reset(dev, 1); break; @@ -1224,10 +1217,9 @@ static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list, } } - if (dev->stop && !dev->wd_pending) { - dev->wd_stopped = true; + if (dev->wd_state == MEI_WD_STOPPING) { + dev->wd_state = MEI_WD_IDLE; wake_up_interruptible(&dev->wait_stop_wd); - return 0; } if (dev->extra_write_index) { @@ -1240,7 +1232,7 @@ static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list, *slots -= dev->extra_write_index; dev->extra_write_index = 0; } - if (dev->mei_state == MEI_ENABLED) { + if (dev->dev_state == MEI_DEV_ENABLED) { if (dev->wd_pending && mei_flow_ctrl_creds(dev, &dev->wd_cl) > 0) { if (mei_wd_send(dev)) @@ -1250,14 +1242,12 @@ static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list, dev->wd_pending = false; - if (dev->wd_timeout) - *slots -= mei_data2slots(MEI_START_WD_DATA_SIZE); + if (dev->wd_state == MEI_WD_RUNNING) + *slots -= mei_data2slots(MEI_WD_START_MSG_SIZE); else - *slots -= mei_data2slots(MEI_WD_PARAMS_SIZE); + *slots -= mei_data2slots(MEI_WD_STOP_MSG_SIZE); } } - if (dev->stop) - return -ENODEV; /* complete control write list CB */ dev_dbg(&dev->pdev->dev, "complete control write list cb.\n"); @@ -1361,8 +1351,8 @@ void mei_timer(struct work_struct *work) mutex_lock(&dev->device_lock); - if (dev->mei_state != MEI_ENABLED) { - if (dev->mei_state == MEI_INIT_CLIENTS) { + if (dev->dev_state != MEI_DEV_ENABLED) { + if (dev->dev_state == MEI_DEV_INIT_CLIENTS) { if (dev->init_clients_timer) { if (--dev->init_clients_timer == 0) { dev_dbg(&dev->pdev->dev, "IMEI reset due to init clients timeout ,init clients state = %d.\n", @@ -1484,8 +1474,8 @@ irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id) /* check if ME wants a reset */ if ((dev->me_hw_state & ME_RDY_HRA) == 0 && - dev->mei_state != MEI_RESETING && - dev->mei_state != MEI_INITIALIZING) { + dev->dev_state != MEI_DEV_RESETING && + dev->dev_state != MEI_DEV_INITIALIZING) { dev_dbg(&dev->pdev->dev, "FW not ready.\n"); mei_reset(dev, 1); mutex_unlock(&dev->device_lock); @@ -1498,7 +1488,7 @@ irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id) dev_dbg(&dev->pdev->dev, "we need to start the dev.\n"); dev->host_hw_state |= (H_IE | H_IG | H_RDY); mei_hcsr_set(dev); - dev->mei_state = MEI_INIT_CLIENTS; + dev->dev_state = MEI_DEV_INIT_CLIENTS; dev_dbg(&dev->pdev->dev, "link is established start sending messages.\n"); /* link is established * start sending messages. diff --git a/drivers/misc/mei/iorw.c b/drivers/misc/mei/iorw.c index 50f52e21f58..fcba98eb892 100644 --- a/drivers/misc/mei/iorw.c +++ b/drivers/misc/mei/iorw.c @@ -38,7 +38,31 @@ #include <linux/mei.h> #include "interface.h" +/** + * mei_me_cl_by_id return index to me_clients for client_id + * + * @dev: the device structure + * @client_id: me client id + * + * Locking: called under "dev->device_lock" lock + * + * returns index on success, -ENOENT on failure. + */ +int mei_me_cl_by_id(struct mei_device *dev, u8 client_id) +{ + int i; + for (i = 0; i < dev->me_clients_num; i++) + if (dev->me_clients[i].client_id == client_id) + break; + if (WARN_ON(dev->me_clients[i].client_id != client_id)) + return -ENOENT; + + if (i == dev->me_clients_num) + return -ENOENT; + + return i; +} /** * mei_ioctl_connect_client - the connect to fw client IOCTL function @@ -84,7 +108,7 @@ int mei_ioctl_connect_client(struct file *file, cb->major_file_operations = MEI_IOCTL; - if (dev->mei_state != MEI_ENABLED) { + if (dev->dev_state != MEI_DEV_ENABLED) { rets = -ENODEV; goto end; } @@ -95,7 +119,7 @@ int mei_ioctl_connect_client(struct file *file, } /* find ME client we're trying to connect to */ - i = mei_find_me_client_index(dev, data->in_client_uuid); + i = mei_me_cl_by_uuid(dev, &data->in_client_uuid); if (i >= 0 && !dev->me_clients[i].props.fixed_address) { cl->me_client_id = dev->me_clients[i].client_id; cl->state = MEI_FILE_CONNECTING; @@ -273,19 +297,12 @@ int amthi_read(struct mei_device *dev, struct file *file, return -ETIMEDOUT; } - for (i = 0; i < dev->me_clients_num; i++) { - if (dev->me_clients[i].client_id == - dev->iamthif_cl.me_client_id) - break; - } + i = mei_me_cl_by_id(dev, dev->iamthif_cl.me_client_id); - if (i == dev->me_clients_num) { + if (i < 0) { dev_dbg(&dev->pdev->dev, "amthi client not found.\n"); return -ENODEV; } - if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id)) - return -ENODEV; - dev_dbg(&dev->pdev->dev, "checking amthi data\n"); cb = find_amthi_read_list_entry(dev, file); @@ -316,8 +333,7 @@ int amthi_read(struct mei_device *dev, struct file *file, dev->iamthif_timer = 0; if (cb) { - timeout = cb->read_time + - msecs_to_jiffies(IAMTHIF_READ_TIMER); + timeout = cb->read_time + msecs_to_jiffies(IAMTHIF_READ_TIMER); dev_dbg(&dev->pdev->dev, "amthi timeout = %lud\n", timeout); @@ -386,7 +402,7 @@ int mei_start_read(struct mei_device *dev, struct mei_cl *cl) if (cl->state != MEI_FILE_CONNECTED) return -ENODEV; - if (dev->mei_state != MEI_ENABLED) + if (dev->dev_state != MEI_DEV_ENABLED) return -ENODEV; dev_dbg(&dev->pdev->dev, "check if read is pending.\n"); @@ -401,19 +417,8 @@ int mei_start_read(struct mei_device *dev, struct mei_cl *cl) dev_dbg(&dev->pdev->dev, "allocation call back successful. host client = %d, ME client = %d\n", cl->host_client_id, cl->me_client_id); - - for (i = 0; i < dev->me_clients_num; i++) { - if (dev->me_clients[i].client_id == cl->me_client_id) - break; - - } - - if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id)) { - rets = -ENODEV; - goto unlock; - } - - if (i == dev->me_clients_num) { + i = mei_me_cl_by_id(dev, cl->me_client_id); + if (i < 0) { rets = -ENODEV; goto unlock; } diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 7422c765284..e8b0858132c 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -41,11 +41,8 @@ #include <linux/mei.h> #include "interface.h" -static const char mei_driver_name[] = "mei"; - -/* The device pointer */ -/* Currently this driver works as long as there is only a single AMT device. */ -struct pci_dev *mei_device; +/* AMT device is a singleton on the platform */ +static struct pci_dev *mei_pdev; /* mei_pci_tbl - PCI Device ID Table */ static DEFINE_PCI_DEVICE_TABLE(mei_pci_tbl) = { @@ -80,6 +77,8 @@ static DEFINE_PCI_DEVICE_TABLE(mei_pci_tbl) = { {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_1)}, {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_2)}, {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_3)}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_LPT)}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_LPT_LP)}, /* required last entry */ {0, } @@ -220,10 +219,10 @@ static int mei_open(struct inode *inode, struct file *file) int err; err = -ENODEV; - if (!mei_device) + if (!mei_pdev) goto out; - dev = pci_get_drvdata(mei_device); + dev = pci_get_drvdata(mei_pdev); if (!dev) goto out; @@ -234,18 +233,24 @@ static int mei_open(struct inode *inode, struct file *file) goto out_unlock; err = -ENODEV; - if (dev->mei_state != MEI_ENABLED) { - dev_dbg(&dev->pdev->dev, "mei_state != MEI_ENABLED mei_state= %d\n", - dev->mei_state); + if (dev->dev_state != MEI_DEV_ENABLED) { + dev_dbg(&dev->pdev->dev, "dev_state != MEI_ENABLED dev_state = %s\n", + mei_dev_state_str(dev->dev_state)); goto out_unlock; } err = -EMFILE; - if (dev->open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) + if (dev->open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) { + dev_err(&dev->pdev->dev, "open_handle_count exceded %d", + MEI_MAX_OPEN_HANDLE_COUNT); goto out_unlock; + } cl_id = find_first_zero_bit(dev->host_clients_map, MEI_CLIENTS_MAX); - if (cl_id >= MEI_CLIENTS_MAX) + if (cl_id >= MEI_CLIENTS_MAX) { + dev_err(&dev->pdev->dev, "client_id exceded %d", + MEI_CLIENTS_MAX) ; goto out_unlock; + } cl->host_client_id = cl_id; @@ -386,17 +391,16 @@ static ssize_t mei_read(struct file *file, char __user *ubuf, dev = cl->dev; mutex_lock(&dev->device_lock); - if (dev->mei_state != MEI_ENABLED) { + if (dev->dev_state != MEI_DEV_ENABLED) { rets = -ENODEV; goto out; } if ((cl->sm_state & MEI_WD_STATE_INDEPENDENCE_MSG_SENT) == 0) { /* Do not allow to read watchdog client */ - i = mei_find_me_client_index(dev, mei_wd_guid); + i = mei_me_cl_by_uuid(dev, &mei_wd_guid); if (i >= 0) { struct mei_me_client *me_client = &dev->me_clients[i]; - if (cl->me_client_id == me_client->client_id) { rets = -EBADF; goto out; @@ -541,7 +545,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, mutex_lock(&dev->device_lock); - if (dev->mei_state != MEI_ENABLED) { + if (dev->dev_state != MEI_DEV_ENABLED) { mutex_unlock(&dev->device_lock); return -ENODEV; } @@ -616,26 +620,16 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, rets = -ENOMEM; goto unlock_dev; } - if (dev->mei_state != MEI_ENABLED) { + if (dev->dev_state != MEI_DEV_ENABLED) { rets = -ENODEV; goto unlock_dev; } - for (i = 0; i < dev->me_clients_num; i++) { - if (dev->me_clients[i].client_id == - dev->iamthif_cl.me_client_id) - break; - } - - if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id)) { + i = mei_me_cl_by_id(dev, dev->iamthif_cl.me_client_id); + if (i < 0) { rets = -ENODEV; goto unlock_dev; } - if (i == dev->me_clients_num || - (dev->me_clients[i].client_id != - dev->iamthif_cl.me_client_id)) { - rets = -ENODEV; - goto unlock_dev; - } else if (length > dev->me_clients[i].props.max_msg_length || + if (length > dev->me_clients[i].props.max_msg_length || length <= 0) { rets = -EMSGSIZE; goto unlock_dev; @@ -688,16 +682,8 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, cl->me_client_id); goto unlock_dev; } - for (i = 0; i < dev->me_clients_num; i++) { - if (dev->me_clients[i].client_id == - cl->me_client_id) - break; - } - if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id)) { - rets = -ENODEV; - goto unlock_dev; - } - if (i == dev->me_clients_num) { + i = mei_me_cl_by_id(dev, cl->me_client_id); + if (i < 0) { rets = -ENODEV; goto unlock_dev; } @@ -790,7 +776,7 @@ static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data) dev_dbg(&dev->pdev->dev, "IOCTL cmd = 0x%x", cmd); mutex_lock(&dev->device_lock); - if (dev->mei_state != MEI_ENABLED) { + if (dev->dev_state != MEI_DEV_ENABLED) { rets = -ENODEV; goto out; } @@ -869,7 +855,7 @@ static unsigned int mei_poll(struct file *file, poll_table *wait) mutex_lock(&dev->device_lock); - if (dev->mei_state != MEI_ENABLED) + if (dev->dev_state != MEI_DEV_ENABLED) goto out; @@ -966,7 +952,7 @@ static int __devinit mei_probe(struct pci_dev *pdev, goto end; } - if (mei_device) { + if (mei_pdev) { err = -EEXIST; goto end; } @@ -979,7 +965,7 @@ static int __devinit mei_probe(struct pci_dev *pdev, /* set PCI host mastering */ pci_set_master(pdev); /* pci request regions for mei driver */ - err = pci_request_regions(pdev, mei_driver_name); + err = pci_request_regions(pdev, KBUILD_MODNAME); if (err) { dev_err(&pdev->dev, "failed to get pci regions.\n"); goto disable_device; @@ -1004,12 +990,12 @@ static int __devinit mei_probe(struct pci_dev *pdev, err = request_threaded_irq(pdev->irq, NULL, mei_interrupt_thread_handler, - IRQF_ONESHOT, mei_driver_name, dev); + IRQF_ONESHOT, KBUILD_MODNAME, dev); else err = request_threaded_irq(pdev->irq, mei_interrupt_quick_handler, mei_interrupt_thread_handler, - IRQF_SHARED, mei_driver_name, dev); + IRQF_SHARED, KBUILD_MODNAME, dev); if (err) { dev_err(&pdev->dev, "request_threaded_irq failure. irq = %d\n", @@ -1027,7 +1013,7 @@ static int __devinit mei_probe(struct pci_dev *pdev, if (err) goto release_irq; - mei_device = pdev; + mei_pdev = pdev; pci_set_drvdata(pdev, dev); @@ -1072,7 +1058,7 @@ static void __devexit mei_remove(struct pci_dev *pdev) { struct mei_device *dev; - if (mei_device != pdev) + if (mei_pdev != pdev) return; dev = pci_get_drvdata(pdev); @@ -1081,9 +1067,11 @@ static void __devexit mei_remove(struct pci_dev *pdev) mutex_lock(&dev->device_lock); - mei_wd_stop(dev, false); + cancel_delayed_work(&dev->timer_work); - mei_device = NULL; + mei_wd_stop(dev); + + mei_pdev = NULL; if (dev->iamthif_cl.state == MEI_FILE_CONNECTED) { dev->iamthif_cl.state = MEI_FILE_DISCONNECTING; @@ -1136,12 +1124,15 @@ static int mei_pci_suspend(struct device *device) if (!dev) return -ENODEV; mutex_lock(&dev->device_lock); + + cancel_delayed_work(&dev->timer_work); + /* Stop watchdog if exists */ - err = mei_wd_stop(dev, true); + err = mei_wd_stop(dev); /* Set new mei state */ - if (dev->mei_state == MEI_ENABLED || - dev->mei_state == MEI_RECOVERING_FROM_RESET) { - dev->mei_state = MEI_POWER_DOWN; + if (dev->dev_state == MEI_DEV_ENABLED || + dev->dev_state == MEI_DEV_RECOVERING_FROM_RESET) { + dev->dev_state = MEI_DEV_POWER_DOWN; mei_reset(dev, 0); } mutex_unlock(&dev->device_lock); @@ -1169,12 +1160,12 @@ static int mei_pci_resume(struct device *device) err = request_threaded_irq(pdev->irq, NULL, mei_interrupt_thread_handler, - IRQF_ONESHOT, mei_driver_name, dev); + IRQF_ONESHOT, KBUILD_MODNAME, dev); else err = request_threaded_irq(pdev->irq, mei_interrupt_quick_handler, mei_interrupt_thread_handler, - IRQF_SHARED, mei_driver_name, dev); + IRQF_SHARED, KBUILD_MODNAME, dev); if (err) { dev_err(&pdev->dev, "request_threaded_irq failed: irq = %d.\n", @@ -1183,7 +1174,7 @@ static int mei_pci_resume(struct device *device) } mutex_lock(&dev->device_lock); - dev->mei_state = MEI_POWER_UP; + dev->dev_state = MEI_DEV_POWER_UP; mei_reset(dev, 1); mutex_unlock(&dev->device_lock); @@ -1201,7 +1192,7 @@ static SIMPLE_DEV_PM_OPS(mei_pm_ops, mei_pci_suspend, mei_pci_resume); * PCI driver structure */ static struct pci_driver mei_driver = { - .name = mei_driver_name, + .name = KBUILD_MODNAME, .id_table = mei_pci_tbl, .probe = mei_probe, .remove = __devexit_p(mei_remove), diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index d61c4ddfc80..adb35fb9281 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -25,18 +25,20 @@ /* * watch dog definition */ -#define MEI_WATCHDOG_DATA_SIZE 16 -#define MEI_START_WD_DATA_SIZE 20 -#define MEI_WD_PARAMS_SIZE 4 +#define MEI_WD_HDR_SIZE 4 +#define MEI_WD_STOP_MSG_SIZE MEI_WD_HDR_SIZE +#define MEI_WD_START_MSG_SIZE (MEI_WD_HDR_SIZE + 16) + +#define MEI_WD_DEFAULT_TIMEOUT 120 /* seconds */ +#define MEI_WD_MIN_TIMEOUT 120 /* seconds */ +#define MEI_WD_MAX_TIMEOUT 65535 /* seconds */ + +#define MEI_WD_STOP_TIMEOUT 10 /* msecs */ + #define MEI_WD_STATE_INDEPENDENCE_MSG_SENT (1 << 0) #define MEI_RD_MSG_BUF_SIZE (128 * sizeof(u32)) -/* - * MEI PCI Device object - */ -extern struct pci_dev *mei_device; - /* * AMTHI Client UUID @@ -54,19 +56,21 @@ extern const uuid_le mei_wd_guid; extern const u8 mei_wd_state_independence_msg[3][4]; /* + * Number of Maximum MEI Clients + */ +#define MEI_CLIENTS_MAX 256 + +/* * Number of File descriptors/handles * that can be opened to the driver. * - * Limit to 253: 255 Total Clients + * Limit to 253: 256 Total Clients + * minus internal client for MEI Bus Messags * minus internal client for AMTHI * minus internal client for Watchdog */ -#define MEI_MAX_OPEN_HANDLE_COUNT 253 +#define MEI_MAX_OPEN_HANDLE_COUNT (MEI_CLIENTS_MAX - 3) -/* - * Number of Maximum MEI Clients - */ -#define MEI_CLIENTS_MAX 255 /* File state */ enum file_state { @@ -78,17 +82,19 @@ enum file_state { }; /* MEI device states */ -enum mei_states { - MEI_INITIALIZING = 0, - MEI_INIT_CLIENTS, - MEI_ENABLED, - MEI_RESETING, - MEI_DISABLED, - MEI_RECOVERING_FROM_RESET, - MEI_POWER_DOWN, - MEI_POWER_UP +enum mei_dev_state { + MEI_DEV_INITIALIZING = 0, + MEI_DEV_INIT_CLIENTS, + MEI_DEV_ENABLED, + MEI_DEV_RESETING, + MEI_DEV_DISABLED, + MEI_DEV_RECOVERING_FROM_RESET, + MEI_DEV_POWER_DOWN, + MEI_DEV_POWER_UP }; +const char *mei_dev_state_str(int state); + /* init clients states*/ enum mei_init_clients_states { MEI_START_MESSAGE = 0, @@ -113,6 +119,12 @@ enum mei_file_transaction_states { MEI_READ_COMPLETE }; +enum mei_wd_states { + MEI_WD_IDLE, + MEI_WD_RUNNING, + MEI_WD_STOPPING, +}; + /* MEI CB */ enum mei_cb_major_types { MEI_READ = 0, @@ -128,7 +140,7 @@ enum mei_cb_major_types { struct mei_message_data { u32 size; unsigned char *data; -} __packed; +}; struct mei_cl_cb { @@ -218,10 +230,9 @@ struct mei_device { /* * mei device states */ - enum mei_states mei_state; + enum mei_dev_state dev_state; enum mei_init_clients_states init_clients_state; u16 init_clients_timer; - bool stop; bool need_reset; u32 extra_write_index; @@ -241,12 +252,11 @@ struct mei_device { bool mei_host_buffer_is_empty; struct mei_cl wd_cl; + enum mei_wd_states wd_state; bool wd_interface_reg; bool wd_pending; - bool wd_stopped; - bool wd_bypass; /* if false, don't refresh watchdog ME client */ - u16 wd_timeout; /* seconds ((wd_data[1] << 8) + wd_data[0]) */ - unsigned char wd_data[MEI_START_WD_DATA_SIZE]; + u16 wd_timeout; + unsigned char wd_data[MEI_WD_START_MSG_SIZE]; struct file *iamthif_file_object; @@ -279,9 +289,10 @@ void mei_host_init_iamthif(struct mei_device *dev); void mei_allocate_me_clients_storage(struct mei_device *dev); -u8 mei_find_me_client_update_filext(struct mei_device *dev, - struct mei_cl *priv, - const uuid_le *cguid, u8 client_id); +int mei_me_cl_update_filext(struct mei_device *dev, struct mei_cl *cl, + const uuid_le *cguid, u8 host_client_id); +int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *cuuid); +int mei_me_cl_by_id(struct mei_device *dev, u8 client_id); /* * MEI IO List Functions @@ -348,7 +359,6 @@ void mei_run_next_iamthif_cmd(struct mei_device *dev); void mei_free_cb_private(struct mei_cl_cb *priv_cb); -int mei_find_me_client_index(const struct mei_device *dev, uuid_le cuuid); /* * Register Access Function diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c index 5133fd77b91..d96c537f046 100644 --- a/drivers/misc/mei/wd.c +++ b/drivers/misc/mei/wd.c @@ -48,8 +48,8 @@ const uuid_le mei_wd_guid = UUID_LE(0x05B79A6F, 0x4628, 0x4D7F, 0x89, static void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout) { dev_dbg(&dev->pdev->dev, "wd: set timeout=%d.\n", timeout); - memcpy(dev->wd_data, mei_start_wd_params, MEI_WD_PARAMS_SIZE); - memcpy(dev->wd_data + MEI_WD_PARAMS_SIZE, &timeout, sizeof(u16)); + memcpy(dev->wd_data, mei_start_wd_params, MEI_WD_HDR_SIZE); + memcpy(dev->wd_data + MEI_WD_HDR_SIZE, &timeout, sizeof(u16)); } /** @@ -66,10 +66,11 @@ int mei_wd_host_init(struct mei_device *dev) /* look for WD client and connect to it */ dev->wd_cl.state = MEI_FILE_DISCONNECTED; - dev->wd_timeout = AMT_WD_DEFAULT_TIMEOUT; + dev->wd_timeout = MEI_WD_DEFAULT_TIMEOUT; + dev->wd_state = MEI_WD_IDLE; /* find ME WD client */ - mei_find_me_client_update_filext(dev, &dev->wd_cl, + mei_me_cl_update_filext(dev, &dev->wd_cl, &mei_wd_guid, MEI_WD_HOST_CLIENT_ID); dev_dbg(&dev->pdev->dev, "wd: check client\n"); @@ -108,10 +109,10 @@ int mei_wd_send(struct mei_device *dev) mei_hdr->msg_complete = 1; mei_hdr->reserved = 0; - if (!memcmp(dev->wd_data, mei_start_wd_params, MEI_WD_PARAMS_SIZE)) - mei_hdr->length = MEI_START_WD_DATA_SIZE; - else if (!memcmp(dev->wd_data, mei_stop_wd_params, MEI_WD_PARAMS_SIZE)) - mei_hdr->length = MEI_WD_PARAMS_SIZE; + if (!memcmp(dev->wd_data, mei_start_wd_params, MEI_WD_HDR_SIZE)) + mei_hdr->length = MEI_WD_START_MSG_SIZE; + else if (!memcmp(dev->wd_data, mei_stop_wd_params, MEI_WD_HDR_SIZE)) + mei_hdr->length = MEI_WD_STOP_MSG_SIZE; else return -EINVAL; @@ -128,18 +129,17 @@ int mei_wd_send(struct mei_device *dev) * -EIO when message send fails * -EINVAL when invalid message is to be sent */ -int mei_wd_stop(struct mei_device *dev, bool preserve) +int mei_wd_stop(struct mei_device *dev) { int ret; - u16 wd_timeout = dev->wd_timeout; - cancel_delayed_work(&dev->timer_work); - if (dev->wd_cl.state != MEI_FILE_CONNECTED || !dev->wd_timeout) + if (dev->wd_cl.state != MEI_FILE_CONNECTED || + dev->wd_state != MEI_WD_RUNNING) return 0; - dev->wd_timeout = 0; - memcpy(dev->wd_data, mei_stop_wd_params, MEI_WD_PARAMS_SIZE); - dev->stop = true; + memcpy(dev->wd_data, mei_stop_wd_params, MEI_WD_STOP_MSG_SIZE); + + dev->wd_state = MEI_WD_STOPPING; ret = mei_flow_ctrl_creds(dev, &dev->wd_cl); if (ret < 0) @@ -161,13 +161,14 @@ int mei_wd_stop(struct mei_device *dev, bool preserve) } else { dev->wd_pending = true; } - dev->wd_stopped = false; + mutex_unlock(&dev->device_lock); ret = wait_event_interruptible_timeout(dev->wait_stop_wd, - dev->wd_stopped, 10 * HZ); + dev->wd_state == MEI_WD_IDLE, + msecs_to_jiffies(MEI_WD_STOP_TIMEOUT)); mutex_lock(&dev->device_lock); - if (dev->wd_stopped) { + if (dev->wd_state == MEI_WD_IDLE) { dev_dbg(&dev->pdev->dev, "wd: stop completed ret=%d.\n", ret); ret = 0; } else { @@ -177,9 +178,6 @@ int mei_wd_stop(struct mei_device *dev, bool preserve) "wd: stop failed to complete ret=%d.\n", ret); } - if (preserve) - dev->wd_timeout = wd_timeout; - out: return ret; } @@ -196,16 +194,16 @@ static int mei_wd_ops_start(struct watchdog_device *wd_dev) int err = -ENODEV; struct mei_device *dev; - dev = pci_get_drvdata(mei_device); + dev = watchdog_get_drvdata(wd_dev); if (!dev) return -ENODEV; mutex_lock(&dev->device_lock); - if (dev->mei_state != MEI_ENABLED) { + if (dev->dev_state != MEI_DEV_ENABLED) { dev_dbg(&dev->pdev->dev, - "wd: mei_state != MEI_ENABLED mei_state = %d\n", - dev->mei_state); + "wd: dev_state != MEI_DEV_ENABLED dev_state = %s\n", + mei_dev_state_str(dev->dev_state)); goto end_unlock; } @@ -233,13 +231,13 @@ end_unlock: static int mei_wd_ops_stop(struct watchdog_device *wd_dev) { struct mei_device *dev; - dev = pci_get_drvdata(mei_device); + dev = watchdog_get_drvdata(wd_dev); if (!dev) return -ENODEV; mutex_lock(&dev->device_lock); - mei_wd_stop(dev, false); + mei_wd_stop(dev); mutex_unlock(&dev->device_lock); return 0; @@ -256,8 +254,8 @@ static int mei_wd_ops_ping(struct watchdog_device *wd_dev) { int ret = 0; struct mei_device *dev; - dev = pci_get_drvdata(mei_device); + dev = watchdog_get_drvdata(wd_dev); if (!dev) return -ENODEV; @@ -269,6 +267,8 @@ static int mei_wd_ops_ping(struct watchdog_device *wd_dev) goto end; } + dev->wd_state = MEI_WD_RUNNING; + /* Check if we can send the ping to HW*/ if (dev->mei_host_buffer_is_empty && mei_flow_ctrl_creds(dev, &dev->wd_cl) > 0) { @@ -309,13 +309,13 @@ end: static int mei_wd_ops_set_timeout(struct watchdog_device *wd_dev, unsigned int timeout) { struct mei_device *dev; - dev = pci_get_drvdata(mei_device); + dev = watchdog_get_drvdata(wd_dev); if (!dev) return -ENODEV; /* Check Timeout value */ - if (timeout < AMT_WD_MIN_TIMEOUT || timeout > AMT_WD_MAX_TIMEOUT) + if (timeout < MEI_WD_MIN_TIMEOUT || timeout > MEI_WD_MAX_TIMEOUT) return -EINVAL; mutex_lock(&dev->device_lock); @@ -341,37 +341,42 @@ static const struct watchdog_ops wd_ops = { }; static const struct watchdog_info wd_info = { .identity = INTEL_AMT_WATCHDOG_ID, - .options = WDIOF_KEEPALIVEPING | WDIOF_ALARMONLY, + .options = WDIOF_KEEPALIVEPING | + WDIOF_SETTIMEOUT | + WDIOF_ALARMONLY, }; static struct watchdog_device amt_wd_dev = { .info = &wd_info, .ops = &wd_ops, - .timeout = AMT_WD_DEFAULT_TIMEOUT, - .min_timeout = AMT_WD_MIN_TIMEOUT, - .max_timeout = AMT_WD_MAX_TIMEOUT, + .timeout = MEI_WD_DEFAULT_TIMEOUT, + .min_timeout = MEI_WD_MIN_TIMEOUT, + .max_timeout = MEI_WD_MAX_TIMEOUT, }; -void mei_watchdog_register(struct mei_device *dev) +void mei_watchdog_register(struct mei_device *dev) { - dev_dbg(&dev->pdev->dev, "dev->wd_timeout =%d.\n", dev->wd_timeout); - if (watchdog_register_device(&amt_wd_dev)) { dev_err(&dev->pdev->dev, "wd: unable to register watchdog device.\n"); dev->wd_interface_reg = false; - } else { - dev_dbg(&dev->pdev->dev, - "wd: successfully register watchdog interface.\n"); - dev->wd_interface_reg = true; + return; } + + dev_dbg(&dev->pdev->dev, + "wd: successfully register watchdog interface.\n"); + dev->wd_interface_reg = true; + watchdog_set_drvdata(&amt_wd_dev, dev); } void mei_watchdog_unregister(struct mei_device *dev) { - if (dev->wd_interface_reg) - watchdog_unregister_device(&amt_wd_dev); + if (!dev->wd_interface_reg) + return; + + watchdog_set_drvdata(&amt_wd_dev, NULL); + watchdog_unregister_device(&amt_wd_dev); dev->wd_interface_reg = false; } diff --git a/drivers/misc/pch_phub.c b/drivers/misc/pch_phub.c index 9fbcacd703d..c9f20dae185 100644 --- a/drivers/misc/pch_phub.c +++ b/drivers/misc/pch_phub.c @@ -699,7 +699,7 @@ static int __devinit pch_phub_probe(struct pci_dev *pdev, chip->pch_phub_base_address = pci_iomap(pdev, 1, 0); - if (chip->pch_phub_base_address == 0) { + if (chip->pch_phub_base_address == NULL) { dev_err(&pdev->dev, "%s : pci_iomap FAILED", __func__); ret = -ENOMEM; goto err_pci_iomap; @@ -893,18 +893,7 @@ static struct pci_driver pch_phub_driver = { .resume = pch_phub_resume }; -static int __init pch_phub_pci_init(void) -{ - return pci_register_driver(&pch_phub_driver); -} - -static void __exit pch_phub_pci_exit(void) -{ - pci_unregister_driver(&pch_phub_driver); -} - -module_init(pch_phub_pci_init); -module_exit(pch_phub_pci_exit); +module_pci_driver(pch_phub_driver); MODULE_DESCRIPTION("Intel EG20T PCH/LAPIS Semiconductor IOH(ML7213/ML7223) PHUB"); MODULE_LICENSE("GPL"); diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c index acfaeeb9e01..46937b10726 100644 --- a/drivers/misc/ti-st/st_core.c +++ b/drivers/misc/ti-st/st_core.c @@ -30,11 +30,13 @@ #include <linux/ti_wilink_st.h> +extern void st_kim_recv(void *, const unsigned char *, long); +void st_int_recv(void *, const unsigned char *, long); /* function pointer pointing to either, * st_kim_recv during registration to receive fw download responses * st_int_recv after registration to receive proto stack responses */ -void (*st_recv) (void*, const unsigned char*, long); +static void (*st_recv) (void *, const unsigned char *, long); /********************************************************************/ static void add_channel_to_table(struct st_data_s *st_gdata, @@ -100,7 +102,7 @@ int st_int_write(struct st_data_s *st_gdata, * push the skb received to relevant * protocol stacks */ -void st_send_frame(unsigned char chnl_id, struct st_data_s *st_gdata) +static void st_send_frame(unsigned char chnl_id, struct st_data_s *st_gdata) { pr_debug(" %s(prot:%d) ", __func__, chnl_id); @@ -140,7 +142,7 @@ void st_send_frame(unsigned char chnl_id, struct st_data_s *st_gdata) * This function is being called with spin lock held, protocol drivers are * only expected to complete their waits and do nothing more than that. */ -void st_reg_complete(struct st_data_s *st_gdata, char err) +static void st_reg_complete(struct st_data_s *st_gdata, char err) { unsigned char i = 0; pr_info(" %s ", __func__); @@ -379,7 +381,7 @@ done: * completely, return that skb which has the pending data. * In normal cases, return top of txq. */ -struct sk_buff *st_int_dequeue(struct st_data_s *st_gdata) +static struct sk_buff *st_int_dequeue(struct st_data_s *st_gdata) { struct sk_buff *returning_skb; @@ -401,7 +403,7 @@ struct sk_buff *st_int_dequeue(struct st_data_s *st_gdata) * txq and waitq needs protection since the other contexts * may be sending data, waking up chip. */ -void st_int_enqueue(struct st_data_s *st_gdata, struct sk_buff *skb) +static void st_int_enqueue(struct st_data_s *st_gdata, struct sk_buff *skb) { unsigned long flags = 0; diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c index 7c14f8fd98d..04a819944f6 100644 --- a/drivers/misc/ti-st/st_kim.c +++ b/drivers/misc/ti-st/st_kim.c @@ -63,10 +63,27 @@ static struct platform_device *st_get_plat_device(int id) * in case of error don't complete so that waiting for proper * response times out */ -void validate_firmware_response(struct kim_data_s *kim_gdata) +static void validate_firmware_response(struct kim_data_s *kim_gdata) { struct sk_buff *skb = kim_gdata->rx_skb; - if (unlikely(skb->data[5] != 0)) { + if (!skb) + return; + + /* these magic numbers are the position in the response buffer which + * allows us to distinguish whether the response is for the read + * version info. command + */ + if (skb->data[2] == 0x01 && skb->data[3] == 0x01 && + skb->data[4] == 0x10 && skb->data[5] == 0x00) { + /* fw version response */ + memcpy(kim_gdata->resp_buffer, + kim_gdata->rx_skb->data, + kim_gdata->rx_skb->len); + complete_all(&kim_gdata->kim_rcvd); + kim_gdata->rx_state = ST_W4_PACKET_TYPE; + kim_gdata->rx_skb = NULL; + kim_gdata->rx_count = 0; + } else if (unlikely(skb->data[5] != 0)) { pr_err("no proper response during fw download"); pr_err("data6 %x", skb->data[5]); kfree_skb(skb); @@ -119,7 +136,7 @@ static inline int kim_check_data_len(struct kim_data_s *kim_gdata, int len) * have been observed to come in bursts of different * tty_receive and hence the logic */ -void kim_int_recv(struct kim_data_s *kim_gdata, +static void kim_int_recv(struct kim_data_s *kim_gdata, const unsigned char *data, long count) { const unsigned char *ptr; @@ -207,16 +224,19 @@ static long read_local_version(struct kim_data_s *kim_gdata, char *bts_scr_name) return -EIO; } - if (!wait_for_completion_timeout - (&kim_gdata->kim_rcvd, msecs_to_jiffies(CMD_RESP_TIME))) { + if (!wait_for_completion_interruptible_timeout( + &kim_gdata->kim_rcvd, msecs_to_jiffies(CMD_RESP_TIME))) { pr_err(" waiting for ver info- timed out "); return -ETIMEDOUT; } INIT_COMPLETION(kim_gdata->kim_rcvd); + /* the positions 12 & 13 in the response buffer provide with the + * chip, major & minor numbers + */ version = - MAKEWORD(kim_gdata->resp_buffer[13], - kim_gdata->resp_buffer[14]); + MAKEWORD(kim_gdata->resp_buffer[12], + kim_gdata->resp_buffer[13]); chip = (version & 0x7C00) >> 10; min_ver = (version & 0x007F); maj_ver = (version & 0x0380) >> 7; @@ -236,7 +256,7 @@ static long read_local_version(struct kim_data_s *kim_gdata, char *bts_scr_name) return 0; } -void skip_change_remote_baud(unsigned char **ptr, long *len) +static void skip_change_remote_baud(unsigned char **ptr, long *len) { unsigned char *nxt_action, *cur_action; cur_action = *ptr; @@ -370,9 +390,9 @@ static long download_firmware(struct kim_data_s *kim_gdata) break; case ACTION_WAIT_EVENT: /* wait */ pr_debug("W"); - if (!wait_for_completion_timeout - (&kim_gdata->kim_rcvd, - msecs_to_jiffies(CMD_RESP_TIME))) { + if (!wait_for_completion_interruptible_timeout( + &kim_gdata->kim_rcvd, + msecs_to_jiffies(CMD_RESP_TIME))) { pr_err("response timeout during fw download "); /* timed out */ release_firmware(kim_gdata->fw_entry); @@ -410,16 +430,10 @@ void st_kim_recv(void *disc_data, const unsigned char *data, long count) struct st_data_s *st_gdata = (struct st_data_s *)disc_data; struct kim_data_s *kim_gdata = st_gdata->kim_data; - /* copy to local buffer */ - if (unlikely(data[4] == 0x01 && data[5] == 0x10 && data[0] == 0x04)) { - /* must be the read_ver_cmd */ - memcpy(kim_gdata->resp_buffer, data, count); - complete_all(&kim_gdata->kim_rcvd); - return; - } else { - kim_int_recv(kim_gdata, data, count); - /* either completes or times out */ - } + /* proceed to gather all data and distinguish read fw version response + * from other fw responses when data gathering is complete + */ + kim_int_recv(kim_gdata, data, count); return; } @@ -454,11 +468,6 @@ long st_kim_start(void *kim_data) if (pdata->chip_enable) pdata->chip_enable(kim_gdata); - /* Configure BT nShutdown to HIGH state */ - gpio_set_value(kim_gdata->nshutdown, GPIO_LOW); - mdelay(5); /* FIXME: a proper toggle */ - gpio_set_value(kim_gdata->nshutdown, GPIO_HIGH); - mdelay(100); /* re-initialize the completion */ INIT_COMPLETION(kim_gdata->ldisc_installed); /* send notification to UIM */ @@ -467,8 +476,8 @@ long st_kim_start(void *kim_data) sysfs_notify(&kim_gdata->kim_pdev->dev.kobj, NULL, "install"); /* wait for ldisc to be installed */ - err = wait_for_completion_timeout(&kim_gdata->ldisc_installed, - msecs_to_jiffies(LDISC_TIME)); + err = wait_for_completion_interruptible_timeout( + &kim_gdata->ldisc_installed, msecs_to_jiffies(LDISC_TIME)); if (!err) { /* ldisc installation timeout, * flush uart, power cycle BT_EN */ @@ -500,8 +509,7 @@ long st_kim_start(void *kim_data) * (b) upon failure to either install ldisc or download firmware. * The function is responsible to (a) notify UIM about un-installation, * (b) flush UART if the ldisc was installed. - * (c) reset BT_EN - pull down nshutdown at the end. - * (d) invoke platform's chip disabling routine. + * (c) invoke platform's chip disabling routine. */ long st_kim_stop(void *kim_data) { @@ -526,20 +534,13 @@ long st_kim_stop(void *kim_data) sysfs_notify(&kim_gdata->kim_pdev->dev.kobj, NULL, "install"); /* wait for ldisc to be un-installed */ - err = wait_for_completion_timeout(&kim_gdata->ldisc_installed, - msecs_to_jiffies(LDISC_TIME)); + err = wait_for_completion_interruptible_timeout( + &kim_gdata->ldisc_installed, msecs_to_jiffies(LDISC_TIME)); if (!err) { /* timeout */ pr_err(" timed out waiting for ldisc to be un-installed"); - return -ETIMEDOUT; + err = -ETIMEDOUT; } - /* By default configure BT nShutdown to LOW state */ - gpio_set_value(kim_gdata->nshutdown, GPIO_LOW); - mdelay(1); - gpio_set_value(kim_gdata->nshutdown, GPIO_HIGH); - mdelay(1); - gpio_set_value(kim_gdata->nshutdown, GPIO_LOW); - /* platform specific disable */ if (pdata->chip_disable) pdata->chip_disable(kim_gdata); @@ -701,7 +702,7 @@ static const struct file_operations list_debugfs_fops = { * board-*.c file */ -struct dentry *kim_debugfs_dir; +static struct dentry *kim_debugfs_dir; static int kim_probe(struct platform_device *pdev) { long status; @@ -731,20 +732,6 @@ static int kim_probe(struct platform_device *pdev) /* refer to itself */ kim_gdata->core_data->kim_data = kim_gdata; - /* Claim the chip enable nShutdown gpio from the system */ - kim_gdata->nshutdown = pdata->nshutdown_gpio; - status = gpio_request(kim_gdata->nshutdown, "kim"); - if (unlikely(status)) { - pr_err(" gpio %ld request failed ", kim_gdata->nshutdown); - return status; - } - - /* Configure nShutdown GPIO as output=0 */ - status = gpio_direction_output(kim_gdata->nshutdown, 0); - if (unlikely(status)) { - pr_err(" unable to configure gpio %ld", kim_gdata->nshutdown); - return status; - } /* get reference of pdev for request_firmware */ kim_gdata->kim_pdev = pdev; @@ -780,18 +767,10 @@ static int kim_probe(struct platform_device *pdev) static int kim_remove(struct platform_device *pdev) { - /* free the GPIOs requested */ - struct ti_st_plat_data *pdata = pdev->dev.platform_data; struct kim_data_s *kim_gdata; kim_gdata = dev_get_drvdata(&pdev->dev); - /* Free the Bluetooth/FM/GPIO - * nShutdown gpio from the system - */ - gpio_free(pdata->nshutdown_gpio); - pr_info("nshutdown GPIO Freed"); - debugfs_remove_recursive(kim_debugfs_dir); sysfs_remove_group(&pdev->dev.kobj, &uim_attr_grp); pr_info("sysfs entries removed"); @@ -804,7 +783,7 @@ static int kim_remove(struct platform_device *pdev) return 0; } -int kim_suspend(struct platform_device *pdev, pm_message_t state) +static int kim_suspend(struct platform_device *pdev, pm_message_t state) { struct ti_st_plat_data *pdata = pdev->dev.platform_data; @@ -814,7 +793,7 @@ int kim_suspend(struct platform_device *pdev, pm_message_t state) return -EOPNOTSUPP; } -int kim_resume(struct platform_device *pdev) +static int kim_resume(struct platform_device *pdev) { struct ti_st_plat_data *pdata = pdev->dev.platform_data; diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c index ba247902267..f8d6654391e 100644 --- a/drivers/misc/tifm_7xx1.c +++ b/drivers/misc/tifm_7xx1.c @@ -434,21 +434,9 @@ static struct pci_driver tifm_7xx1_driver = { .resume = tifm_7xx1_resume, }; -static int __init tifm_7xx1_init(void) -{ - return pci_register_driver(&tifm_7xx1_driver); -} - -static void __exit tifm_7xx1_exit(void) -{ - pci_unregister_driver(&tifm_7xx1_driver); -} - +module_pci_driver(tifm_7xx1_driver); MODULE_AUTHOR("Alex Dubov"); MODULE_DESCRIPTION("TI FlashMedia host driver"); MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, tifm_7xx1_pci_tbl); MODULE_VERSION(DRIVER_VERSION); - -module_init(tifm_7xx1_init); -module_exit(tifm_7xx1_exit); diff --git a/drivers/w1/masters/Kconfig b/drivers/w1/masters/Kconfig index 5ceb1cd5019..7e984034a11 100644 --- a/drivers/w1/masters/Kconfig +++ b/drivers/w1/masters/Kconfig @@ -60,7 +60,6 @@ config W1_MASTER_GPIO config HDQ_MASTER_OMAP tristate "OMAP HDQ driver" - depends on ARCH_OMAP2PLUS help Say Y here if you want support for the 1-wire or HDQ Interface on an OMAP processor. diff --git a/drivers/w1/masters/omap_hdq.c b/drivers/w1/masters/omap_hdq.c index 4b0fcf3c2d0..ca8e60bb2f9 100644 --- a/drivers/w1/masters/omap_hdq.c +++ b/drivers/w1/masters/omap_hdq.c @@ -18,9 +18,6 @@ #include <linux/sched.h> #include <linux/pm_runtime.h> -#include <asm/irq.h> -#include <mach/hardware.h> - #include "../w1.h" #include "../w1_int.h" @@ -73,11 +70,11 @@ struct hdq_data { }; static int __devinit omap_hdq_probe(struct platform_device *pdev); -static int omap_hdq_remove(struct platform_device *pdev); +static int __devexit omap_hdq_remove(struct platform_device *pdev); static struct platform_driver omap_hdq_driver = { .probe = omap_hdq_probe, - .remove = omap_hdq_remove, + .remove = __devexit_p(omap_hdq_remove), .driver = { .name = "omap_hdq", }, @@ -538,39 +535,35 @@ static void omap_w1_write_byte(void *_hdq, u8 byte) hdq_data->init_trans = 0; mutex_unlock(&hdq_data->hdq_mutex); } - - return; } static int __devinit omap_hdq_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct hdq_data *hdq_data; struct resource *res; int ret, irq; u8 rev; - hdq_data = kmalloc(sizeof(*hdq_data), GFP_KERNEL); + hdq_data = devm_kzalloc(dev, sizeof(*hdq_data), GFP_KERNEL); if (!hdq_data) { dev_dbg(&pdev->dev, "unable to allocate memory\n"); - ret = -ENOMEM; - goto err_kmalloc; + return -ENOMEM; } - hdq_data->dev = &pdev->dev; + hdq_data->dev = dev; platform_set_drvdata(pdev, hdq_data); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_dbg(&pdev->dev, "unable to get resource\n"); - ret = -ENXIO; - goto err_resource; + return -ENXIO; } - hdq_data->hdq_base = ioremap(res->start, SZ_4K); + hdq_data->hdq_base = devm_request_and_ioremap(dev, res); if (!hdq_data->hdq_base) { dev_dbg(&pdev->dev, "ioremap failed\n"); - ret = -EINVAL; - goto err_ioremap; + return -ENOMEM; } hdq_data->hdq_usecount = 0; @@ -591,7 +584,8 @@ static int __devinit omap_hdq_probe(struct platform_device *pdev) goto err_irq; } - ret = request_irq(irq, hdq_isr, IRQF_DISABLED, "omap_hdq", hdq_data); + ret = devm_request_irq(dev, irq, hdq_isr, IRQF_DISABLED, + "omap_hdq", hdq_data); if (ret < 0) { dev_dbg(&pdev->dev, "could not request irq\n"); goto err_irq; @@ -616,19 +610,10 @@ err_irq: err_w1: pm_runtime_disable(&pdev->dev); - iounmap(hdq_data->hdq_base); - -err_ioremap: -err_resource: - platform_set_drvdata(pdev, NULL); - kfree(hdq_data); - -err_kmalloc: return ret; - } -static int omap_hdq_remove(struct platform_device *pdev) +static int __devexit omap_hdq_remove(struct platform_device *pdev) { struct hdq_data *hdq_data = platform_get_drvdata(pdev); @@ -644,27 +629,11 @@ static int omap_hdq_remove(struct platform_device *pdev) /* remove module dependency */ pm_runtime_disable(&pdev->dev); - free_irq(INT_24XX_HDQ_IRQ, hdq_data); - platform_set_drvdata(pdev, NULL); - iounmap(hdq_data->hdq_base); - kfree(hdq_data); return 0; } -static int __init -omap_hdq_init(void) -{ - return platform_driver_register(&omap_hdq_driver); -} -module_init(omap_hdq_init); - -static void __exit -omap_hdq_exit(void) -{ - platform_driver_unregister(&omap_hdq_driver); -} -module_exit(omap_hdq_exit); +module_platform_driver(omap_hdq_driver); module_param(w1_id, int, S_IRUSR); MODULE_PARM_DESC(w1_id, "1-wire id for the slave detection"); diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c index df600d14974..6012c4ea320 100644 --- a/drivers/w1/masters/w1-gpio.c +++ b/drivers/w1/masters/w1-gpio.c @@ -14,6 +14,8 @@ #include <linux/slab.h> #include <linux/w1-gpio.h> #include <linux/gpio.h> +#include <linux/of_platform.h> +#include <linux/of_gpio.h> #include "../w1.h" #include "../w1_int.h" @@ -42,12 +44,55 @@ static u8 w1_gpio_read_bit(void *data) return gpio_get_value(pdata->pin) ? 1 : 0; } +#ifdef CONFIG_OF +static struct of_device_id w1_gpio_dt_ids[] = { + { .compatible = "w1-gpio" }, + {} +}; +MODULE_DEVICE_TABLE(of, w1_gpio_dt_ids); + +static int w1_gpio_probe_dt(struct platform_device *pdev) +{ + struct w1_gpio_platform_data *pdata = pdev->dev.platform_data; + struct device_node *np = pdev->dev.of_node; + const struct of_device_id *of_id = + of_match_device(w1_gpio_dt_ids, &pdev->dev); + + if (!of_id) + return 0; + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + if (of_get_property(np, "linux,open-drain", NULL)) + pdata->is_open_drain = 1; + + pdata->pin = of_get_gpio(np, 0); + pdata->ext_pullup_enable_pin = of_get_gpio(np, 1); + pdev->dev.platform_data = pdata; + + return 0; +} +#else +static int w1_gpio_probe_dt(struct platform_device *pdev) +{ + return 0; +} +#endif + static int __init w1_gpio_probe(struct platform_device *pdev) { struct w1_bus_master *master; - struct w1_gpio_platform_data *pdata = pdev->dev.platform_data; + struct w1_gpio_platform_data *pdata; int err; + err = w1_gpio_probe_dt(pdev); + if (err < 0) + return err; + + pdata = pdev->dev.platform_data; + if (!pdata) return -ENXIO; @@ -59,6 +104,13 @@ static int __init w1_gpio_probe(struct platform_device *pdev) if (err) goto free_master; + if (gpio_is_valid(pdata->ext_pullup_enable_pin)) { + err = gpio_request_one(pdata->ext_pullup_enable_pin, + GPIOF_INIT_LOW, "w1 pullup"); + if (err < 0) + goto free_gpio; + } + master->data = pdata; master->read_bit = w1_gpio_read_bit; @@ -72,15 +124,21 @@ static int __init w1_gpio_probe(struct platform_device *pdev) err = w1_add_master_device(master); if (err) - goto free_gpio; + goto free_gpio_ext_pu; if (pdata->enable_external_pullup) pdata->enable_external_pullup(1); + if (gpio_is_valid(pdata->ext_pullup_enable_pin)) + gpio_set_value(pdata->ext_pullup_enable_pin, 1); + platform_set_drvdata(pdev, master); return 0; + free_gpio_ext_pu: + if (gpio_is_valid(pdata->ext_pullup_enable_pin)) + gpio_free(pdata->ext_pullup_enable_pin); free_gpio: gpio_free(pdata->pin); free_master: @@ -97,6 +155,9 @@ static int __exit w1_gpio_remove(struct platform_device *pdev) if (pdata->enable_external_pullup) pdata->enable_external_pullup(0); + if (gpio_is_valid(pdata->ext_pullup_enable_pin)) + gpio_set_value(pdata->ext_pullup_enable_pin, 0); + w1_remove_master_device(master); gpio_free(pdata->pin); kfree(master); @@ -135,6 +196,7 @@ static struct platform_driver w1_gpio_driver = { .driver = { .name = "w1-gpio", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(w1_gpio_dt_ids), }, .remove = __exit_p(w1_gpio_remove), .suspend = w1_gpio_suspend, diff --git a/include/linux/ti_wilink_st.h b/include/linux/ti_wilink_st.h index 3ca0269dd0b..932b7639224 100644 --- a/include/linux/ti_wilink_st.h +++ b/include/linux/ti_wilink_st.h @@ -281,9 +281,10 @@ struct kim_data_s { long st_kim_start(void *); long st_kim_stop(void *); -void st_kim_recv(void *, const unsigned char *, long count); void st_kim_complete(void *); void kim_st_list_protocols(struct st_data_s *, void *); +void st_kim_recv(void *, const unsigned char *, long); + /* * BTS headers diff --git a/include/linux/w1-gpio.h b/include/linux/w1-gpio.h index 3adeff82212..065e3ae79ab 100644 --- a/include/linux/w1-gpio.h +++ b/include/linux/w1-gpio.h @@ -19,6 +19,7 @@ struct w1_gpio_platform_data { unsigned int pin; unsigned int is_open_drain:1; void (*enable_external_pullup)(int enable); + unsigned int ext_pullup_enable_pin; }; #endif /* _LINUX_W1_GPIO_H */ |