Re: [patch added to 3.12-stable] Input: i8042 - break load dependency between atkbd/psmouse and i8042

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Sep 22, 2016 at 12:11 AM, Jiri Slaby <jslaby@xxxxxxx> wrote:
> From: Dmitry Torokhov <dmitry.torokhov@xxxxxxxxx>
>
> This patch has been added to the 3.12 stable tree. If you have any
> objections, please let us know.
>

Please make sure you grab the follow up patch initializing
serio->ps2_cmd_mutex in AUX port in i8042.

> ===============
>
> commit 4097461897df91041382ff6fcd2bfa7ee6b2448c upstream.
>
> As explained in 1407814240-4275-1-git-send-email-decui@xxxxxxxxxxxxx we
> have a hard load dependency between i8042 and atkbd which prevents
> keyboard from working on Gen2 Hyper-V VMs.
>
>> hyperv_keyboard invokes serio_interrupt(), which needs a valid serio
>> driver like atkbd.c.  atkbd.c depends on libps2.c because it invokes
>> ps2_command().  libps2.c depends on i8042.c because it invokes
>> i8042_check_port_owner().  As a result, hyperv_keyboard actually
>> depends on i8042.c.
>>
>> For a Generation 2 Hyper-V VM (meaning no i8042 device emulated), if a
>> Linux VM (like Arch Linux) happens to configure CONFIG_SERIO_I8042=m
>> rather than =y, atkbd.ko can't load because i8042.ko can't load(due to
>> no i8042 device emulated) and finally hyperv_keyboard can't work and
>> the user can't input: https://bugs.archlinux.org/task/39820
>> (Ubuntu/RHEL/SUSE aren't affected since they use CONFIG_SERIO_I8042=y)
>
> To break the dependency we move away from using i8042_check_port_owner()
> and instead allow serio port owner specify a mutex that clients should use
> to serialize PS/2 command stream.
>
> Reported-by: Mark Laws <mdl@xxxxxxxx>
> Tested-by: Mark Laws <mdl@xxxxxxxx>
> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@xxxxxxxxx>
> Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
> ---
>  drivers/input/serio/i8042.c  | 16 +---------------
>  drivers/input/serio/libps2.c | 10 ++++------
>  include/linux/i8042.h        |  6 ------
>  include/linux/serio.h        | 24 +++++++++++++++++++-----
>  4 files changed, 24 insertions(+), 32 deletions(-)
>
> diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
> index 42825216e83d..7ecca05bd7a5 100644
> --- a/drivers/input/serio/i8042.c
> +++ b/drivers/input/serio/i8042.c
> @@ -1230,6 +1230,7 @@ static int __init i8042_create_kbd_port(void)
>         serio->start            = i8042_start;
>         serio->stop             = i8042_stop;
>         serio->close            = i8042_port_close;
> +       serio->ps2_cmd_mutex    = &i8042_mutex;
>         serio->port_data        = port;
>         serio->dev.parent       = &i8042_platform_device->dev;
>         strlcpy(serio->name, "i8042 KBD port", sizeof(serio->name));
> @@ -1321,21 +1322,6 @@ static void i8042_unregister_ports(void)
>         }
>  }
>
> -/*
> - * Checks whether port belongs to i8042 controller.
> - */
> -bool i8042_check_port_owner(const struct serio *port)
> -{
> -       int i;
> -
> -       for (i = 0; i < I8042_NUM_PORTS; i++)
> -               if (i8042_ports[i].serio == port)
> -                       return true;
> -
> -       return false;
> -}
> -EXPORT_SYMBOL(i8042_check_port_owner);
> -
>  static void i8042_free_irqs(void)
>  {
>         if (i8042_aux_irq_registered)
> diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c
> index 07a8363f3c5c..b5ec313cb9c9 100644
> --- a/drivers/input/serio/libps2.c
> +++ b/drivers/input/serio/libps2.c
> @@ -57,19 +57,17 @@ EXPORT_SYMBOL(ps2_sendbyte);
>
>  void ps2_begin_command(struct ps2dev *ps2dev)
>  {
> -       mutex_lock(&ps2dev->cmd_mutex);
> +       struct mutex *m = ps2dev->serio->ps2_cmd_mutex ?: &ps2dev->cmd_mutex;
>
> -       if (i8042_check_port_owner(ps2dev->serio))
> -               i8042_lock_chip();
> +       mutex_lock(m);
>  }
>  EXPORT_SYMBOL(ps2_begin_command);
>
>  void ps2_end_command(struct ps2dev *ps2dev)
>  {
> -       if (i8042_check_port_owner(ps2dev->serio))
> -               i8042_unlock_chip();
> +       struct mutex *m = ps2dev->serio->ps2_cmd_mutex ?: &ps2dev->cmd_mutex;
>
> -       mutex_unlock(&ps2dev->cmd_mutex);
> +       mutex_unlock(m);
>  }
>  EXPORT_SYMBOL(ps2_end_command);
>
> diff --git a/include/linux/i8042.h b/include/linux/i8042.h
> index 0f9bafa17a02..d98780ca9604 100644
> --- a/include/linux/i8042.h
> +++ b/include/linux/i8042.h
> @@ -62,7 +62,6 @@ struct serio;
>  void i8042_lock_chip(void);
>  void i8042_unlock_chip(void);
>  int i8042_command(unsigned char *param, int command);
> -bool i8042_check_port_owner(const struct serio *);
>  int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str,
>                                         struct serio *serio));
>  int i8042_remove_filter(bool (*filter)(unsigned char data, unsigned char str,
> @@ -83,11 +82,6 @@ static inline int i8042_command(unsigned char *param, int command)
>         return -ENODEV;
>  }
>
> -static inline bool i8042_check_port_owner(const struct serio *serio)
> -{
> -       return false;
> -}
> -
>  static inline int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str,
>                                         struct serio *serio))
>  {
> diff --git a/include/linux/serio.h b/include/linux/serio.h
> index 9f779c7a2da4..27ae809edd70 100644
> --- a/include/linux/serio.h
> +++ b/include/linux/serio.h
> @@ -29,7 +29,8 @@ struct serio {
>
>         struct serio_device_id id;
>
> -       spinlock_t lock;                /* protects critical sections from port's interrupt handler */
> +       /* Protects critical sections from port's interrupt handler */
> +       spinlock_t lock;
>
>         int (*write)(struct serio *, unsigned char);
>         int (*open)(struct serio *);
> @@ -38,16 +39,29 @@ struct serio {
>         void (*stop)(struct serio *);
>
>         struct serio *parent;
> -       struct list_head child_node;    /* Entry in parent->children list */
> +       /* Entry in parent->children list */
> +       struct list_head child_node;
>         struct list_head children;
> -       unsigned int depth;             /* level of nesting in serio hierarchy */
> +       /* Level of nesting in serio hierarchy */
> +       unsigned int depth;
>
> -       struct serio_driver *drv;       /* accessed from interrupt, must be protected by serio->lock and serio->sem */
> -       struct mutex drv_mutex;         /* protects serio->drv so attributes can pin driver */
> +       /*
> +        * serio->drv is accessed from interrupt handlers; when modifying
> +        * caller should acquire serio->drv_mutex and serio->lock.
> +        */
> +       struct serio_driver *drv;
> +       /* Protects serio->drv so attributes can pin current driver */
> +       struct mutex drv_mutex;
>
>         struct device dev;
>
>         struct list_head node;
> +
> +       /*
> +        * For use by PS/2 layer when several ports share hardware and
> +        * may get indigestion when exposed to concurrent access (i8042).
> +        */
> +       struct mutex *ps2_cmd_mutex;
>  };
>  #define to_serio_port(d)       container_of(d, struct serio, dev)
>
> --
> 2.10.0
>



-- 
Dmitry
--
To unsubscribe from this list: send the line "unsubscribe stable" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]