Merge branch 'for-5.1/i2c-hid' into for-linus
authorJiri Kosina <jkosina@suse.cz>
Tue, 5 Mar 2019 14:42:51 +0000 (15:42 +0100)
committerJiri Kosina <jkosina@suse.cz>
Tue, 5 Mar 2019 14:42:51 +0000 (15:42 +0100)
Fix dmesg flood for Elan touchpanels which are too slow to assert IRQ from Kai-Heng Feng

1  2 
drivers/hid/i2c-hid/i2c-hid-core.c
drivers/hid/intel-ish-hid/ipc/ipc.c
drivers/hid/intel-ish-hid/ishtp/bus.c
drivers/hid/intel-ish-hid/ishtp/bus.h

index c5edfa966343dc098c63af7d4513ffeed02348de,2f940c1de6169724b6f629787496b8bf4d9f9268..90164fed08d35eca2c34250c8b7cb3814ea99f53
@@@ -50,6 -50,7 +50,7 @@@
  #define I2C_HID_QUIRK_NO_IRQ_AFTER_RESET      BIT(1)
  #define I2C_HID_QUIRK_NO_RUNTIME_PM           BIT(2)
  #define I2C_HID_QUIRK_DELAY_AFTER_SLEEP               BIT(3)
+ #define I2C_HID_QUIRK_BOGUS_IRQ                       BIT(4)
  
  /* flags */
  #define I2C_HID_STARTED               0
@@@ -179,8 -180,8 +180,10 @@@ static const struct i2c_hid_quirks 
                I2C_HID_QUIRK_DELAY_AFTER_SLEEP },
        { USB_VENDOR_ID_LG, I2C_DEVICE_ID_LG_8001,
                I2C_HID_QUIRK_NO_RUNTIME_PM },
 +      { I2C_VENDOR_ID_GOODIX, I2C_DEVICE_ID_GOODIX_01F0,
 +              I2C_HID_QUIRK_NO_RUNTIME_PM },
+       { USB_VENDOR_ID_ELAN, HID_ANY_ID,
+                I2C_HID_QUIRK_BOGUS_IRQ },
        { 0, 0 }
  };
  
@@@ -505,6 -506,12 +508,12 @@@ static void i2c_hid_get_input(struct i2
                return;
        }
  
+       if (ihid->quirks & I2C_HID_QUIRK_BOGUS_IRQ && ret_size == 0xffff) {
+               dev_warn_once(&ihid->client->dev, "%s: IRQ triggered but "
+                             "there's no data\n", __func__);
+               return;
+       }
        if ((ret_size > size) || (ret_size < 2)) {
                dev_err(&ihid->client->dev, "%s: incomplete report (%d/%d)\n",
                        __func__, size, ret_size);
index 45e33c7ba9a623d9c0ac0e7a59daa7bee9486919,30d8a639a5bb7c22511a593bce549ad9ac242a6d..96e869118db3767edd40efb02c0f2e71437e6647
@@@ -91,10 -91,7 +91,10 @@@ static bool check_generated_interrupt(s
                        IPC_INT_FROM_ISH_TO_HOST_CHV_AB(pisr_val);
        } else {
                pisr_val = ish_reg_read(dev, IPC_REG_PISR_BXT);
 -              interrupt_generated = IPC_INT_FROM_ISH_TO_HOST_BXT(pisr_val);
 +              interrupt_generated = !!pisr_val;
 +              /* only busy-clear bit is RW, others are RO */
 +              if (pisr_val)
 +                      ish_reg_write(dev, IPC_REG_PISR_BXT, pisr_val);
        }
  
        return interrupt_generated;
@@@ -259,33 -256,22 +259,22 @@@ static int write_ipc_from_queue(struct 
        int     i;
        void    (*ipc_send_compl)(void *);
        void    *ipc_send_compl_prm;
-       static int      out_ipc_locked;
-       unsigned long   out_ipc_flags;
  
        if (dev->dev_state == ISHTP_DEV_DISABLED)
-               return  -EINVAL;
+               return -EINVAL;
  
-       spin_lock_irqsave(&dev->out_ipc_spinlock, out_ipc_flags);
-       if (out_ipc_locked) {
-               spin_unlock_irqrestore(&dev->out_ipc_spinlock, out_ipc_flags);
-               return -EBUSY;
-       }
-       out_ipc_locked = 1;
+       spin_lock_irqsave(&dev->wr_processing_spinlock, flags);
        if (!ish_is_input_ready(dev)) {
-               out_ipc_locked = 0;
-               spin_unlock_irqrestore(&dev->out_ipc_spinlock, out_ipc_flags);
+               spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);
                return -EBUSY;
        }
-       spin_unlock_irqrestore(&dev->out_ipc_spinlock, out_ipc_flags);
  
-       spin_lock_irqsave(&dev->wr_processing_spinlock, flags);
        /*
         * if tx send list is empty - return 0;
         * may happen, as RX_COMPLETE handler doesn't check list emptiness.
         */
        if (list_empty(&dev->wr_processing_list)) {
                spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);
-               out_ipc_locked = 0;
                return  0;
        }
  
                memcpy(&reg, &r_buf[length >> 2], rem);
                ish_reg_write(dev, reg_addr, reg);
        }
+       ish_reg_write(dev, IPC_REG_HOST2ISH_DRBL, doorbell_val);
        /* Flush writes to msg registers and doorbell */
        ish_reg_read(dev, IPC_REG_ISH_HOST_FWSTS);
  
        ++dev->ipc_tx_cnt;
        dev->ipc_tx_bytes_cnt += IPC_HEADER_GET_LENGTH(doorbell_val);
  
-       ish_reg_write(dev, IPC_REG_HOST2ISH_DRBL, doorbell_val);
-       out_ipc_locked = 0;
        ipc_send_compl = ipc_link->ipc_send_compl;
        ipc_send_compl_prm = ipc_link->ipc_send_compl_prm;
        list_del_init(&ipc_link->link);
@@@ -842,11 -827,11 +830,11 @@@ int ish_hw_start(struct ishtp_device *d
  {
        ish_set_host_rdy(dev);
  
 +      set_host_ready(dev);
 +
        /* After that we can enable ISH DMA operation and wakeup ISHFW */
        ish_wakeup(dev);
  
 -      set_host_ready(dev);
 -
        /* wait for FW-initiated reset flow */
        if (!dev->recvd_hw_ready)
                wait_event_interruptible_timeout(dev->wait_hw_ready,
@@@ -917,7 -902,6 +905,6 @@@ struct ishtp_device *ish_dev_init(struc
        init_waitqueue_head(&dev->wait_hw_ready);
  
        spin_lock_init(&dev->wr_processing_spinlock);
-       spin_lock_init(&dev->out_ipc_spinlock);
  
        /* Init IPC processing and free lists */
        INIT_LIST_HEAD(&dev->wr_processing_list);
index efa21d33ad60728b1e80516ae6f9f7467486f207,f358a02325da893f45e1e93c59ef2c4175bdf14a..d5f4b6438d8691721c88129392167e72d3d82893
@@@ -119,7 -119,7 +119,7 @@@ int ishtp_send_msg(struct ishtp_device 
   * Return: This returns IPC send message status.
   */
  int ishtp_write_message(struct ishtp_device *dev, struct ishtp_msg_hdr *hdr,
-                       unsigned char *buf)
+                       void *buf)
  {
        return ishtp_send_msg(dev, hdr, buf, NULL, NULL);
  }
   *
   * Return: fw client index or -ENOENT if not found
   */
 -int ishtp_fw_cl_by_uuid(struct ishtp_device *dev, const uuid_le *uuid)
 +int ishtp_fw_cl_by_uuid(struct ishtp_device *dev, const guid_t *uuid)
  {
 -      int i, res = -ENOENT;
 +      unsigned int i;
  
        for (i = 0; i < dev->fw_clients_num; ++i) {
 -              if (uuid_le_cmp(*uuid, dev->fw_clients[i].props.protocol_name)
 -                              == 0) {
 -                      res = i;
 -                      break;
 -              }
 +              if (guid_equal(uuid, &dev->fw_clients[i].props.protocol_name))
 +                      return i;
        }
 -      return res;
 +      return -ENOENT;
  }
  EXPORT_SYMBOL(ishtp_fw_cl_by_uuid);
  
   * Return: pointer of client information on success, NULL on failure.
   */
  struct ishtp_fw_client *ishtp_fw_cl_get_client(struct ishtp_device *dev,
 -                                              const uuid_le *uuid)
 +                                             const guid_t *uuid)
  {
        int i;
        unsigned long flags;
@@@ -398,7 -401,7 +398,7 @@@ static const struct device_type ishtp_c
   * Return: ishtp_cl_device pointer or NULL on failure
   */
  static struct ishtp_cl_device *ishtp_bus_add_device(struct ishtp_device *dev,
 -                                                  uuid_le uuid, char *name)
 +                                                  guid_t uuid, char *name)
  {
        struct ishtp_cl_device *device;
        int status;
@@@ -626,7 -629,7 +626,7 @@@ int ishtp_bus_new_client(struct ishtp_d
        int     i;
        char    *dev_name;
        struct ishtp_cl_device  *cl_device;
 -      uuid_le device_uuid;
 +      guid_t  device_uuid;
  
        /*
         * For all reported clients, create an unconnected client and add its
         */
        i = dev->fw_client_presentation_num - 1;
        device_uuid = dev->fw_clients[i].props.protocol_name;
 -      dev_name = kasprintf(GFP_KERNEL, "{%pUL}", device_uuid.b);
 +      dev_name = kasprintf(GFP_KERNEL, "{%pUL}", &device_uuid);
        if (!dev_name)
                return  -ENOMEM;
  
@@@ -672,7 -675,8 +672,8 @@@ int ishtp_cl_device_bind(struct ishtp_c
        spin_lock_irqsave(&cl->dev->device_list_lock, flags);
        list_for_each_entry(cl_device, &cl->dev->device_list,
                        device_link) {
-               if (cl_device->fw_client->client_id == cl->fw_client_id) {
+               if (cl_device->fw_client &&
+                   cl_device->fw_client->client_id == cl->fw_client_id) {
                        cl->device = cl_device;
                        rv = 0;
                        break;
@@@ -732,6 -736,7 +733,7 @@@ void ishtp_bus_remove_all_clients(struc
        spin_lock_irqsave(&ishtp_dev->device_list_lock, flags);
        list_for_each_entry_safe(cl_device, n, &ishtp_dev->device_list,
                                 device_link) {
+               cl_device->fw_client = NULL;
                if (warm_reset && cl_device->reference_count)
                        continue;
  
index babf19ba3ff618dc8764fd5d651fe0cbf3390fc7,5c4763d73f8b3a8af3ae8fe2ba15384c6082d8b4..4cf7ad586c37da4eb45d53e9e3c368aa6ccd1270
@@@ -85,7 -85,7 +85,7 @@@ int   ishtp_send_msg(struct ishtp_device 
  /* Write a single-fragment message */
  int   ishtp_write_message(struct ishtp_device *dev,
                            struct ishtp_msg_hdr *hdr,
-                           unsigned char *buf);
+                           void *buf);
  
  /* Use DMA to send/receive messages */
  int ishtp_use_dma_transfer(void);
@@@ -112,8 -112,8 +112,8 @@@ void       ishtp_cl_driver_unregister(struct 
  
  int   ishtp_register_event_cb(struct ishtp_cl_device *device,
                                void (*read_cb)(struct ishtp_cl_device *));
 -int   ishtp_fw_cl_by_uuid(struct ishtp_device *dev, const uuid_le *cuuid);
 +int   ishtp_fw_cl_by_uuid(struct ishtp_device *dev, const guid_t *cuuid);
  struct        ishtp_fw_client *ishtp_fw_cl_get_client(struct ishtp_device *dev,
 -                                              const uuid_le *uuid);
 +                                              const guid_t *uuid);
  
  #endif /* _LINUX_ISHTP_CL_BUS_H */