Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Input: i8042 - break load dependency between atkbd/psmouse and i8042

As explained in 1407814240-4275-1-git-send-email-decui@microsoft.com 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@60hz.org>
Tested-by: Mark Laws <mdl@60hz.org>
Cc: stable@vger.kernel.org
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

+24 -32
+1 -15
drivers/input/serio/i8042.c
··· 1277 1277 serio->start = i8042_start; 1278 1278 serio->stop = i8042_stop; 1279 1279 serio->close = i8042_port_close; 1280 + serio->ps2_cmd_mutex = &i8042_mutex; 1280 1281 serio->port_data = port; 1281 1282 serio->dev.parent = &i8042_platform_device->dev; 1282 1283 strlcpy(serio->name, "i8042 KBD port", sizeof(serio->name)); ··· 1373 1372 } 1374 1373 } 1375 1374 } 1376 - 1377 - /* 1378 - * Checks whether port belongs to i8042 controller. 1379 - */ 1380 - bool i8042_check_port_owner(const struct serio *port) 1381 - { 1382 - int i; 1383 - 1384 - for (i = 0; i < I8042_NUM_PORTS; i++) 1385 - if (i8042_ports[i].serio == port) 1386 - return true; 1387 - 1388 - return false; 1389 - } 1390 - EXPORT_SYMBOL(i8042_check_port_owner); 1391 1375 1392 1376 static void i8042_free_irqs(void) 1393 1377 {
+4 -6
drivers/input/serio/libps2.c
··· 56 56 57 57 void ps2_begin_command(struct ps2dev *ps2dev) 58 58 { 59 - mutex_lock(&ps2dev->cmd_mutex); 59 + struct mutex *m = ps2dev->serio->ps2_cmd_mutex ?: &ps2dev->cmd_mutex; 60 60 61 - if (i8042_check_port_owner(ps2dev->serio)) 62 - i8042_lock_chip(); 61 + mutex_lock(m); 63 62 } 64 63 EXPORT_SYMBOL(ps2_begin_command); 65 64 66 65 void ps2_end_command(struct ps2dev *ps2dev) 67 66 { 68 - if (i8042_check_port_owner(ps2dev->serio)) 69 - i8042_unlock_chip(); 67 + struct mutex *m = ps2dev->serio->ps2_cmd_mutex ?: &ps2dev->cmd_mutex; 70 68 71 - mutex_unlock(&ps2dev->cmd_mutex); 69 + mutex_unlock(m); 72 70 } 73 71 EXPORT_SYMBOL(ps2_end_command); 74 72
-6
include/linux/i8042.h
··· 62 62 void i8042_lock_chip(void); 63 63 void i8042_unlock_chip(void); 64 64 int i8042_command(unsigned char *param, int command); 65 - bool i8042_check_port_owner(const struct serio *); 66 65 int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str, 67 66 struct serio *serio)); 68 67 int i8042_remove_filter(bool (*filter)(unsigned char data, unsigned char str, ··· 80 81 static inline int i8042_command(unsigned char *param, int command) 81 82 { 82 83 return -ENODEV; 83 - } 84 - 85 - static inline bool i8042_check_port_owner(const struct serio *serio) 86 - { 87 - return false; 88 84 } 89 85 90 86 static inline int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str,
+19 -5
include/linux/serio.h
··· 31 31 32 32 struct serio_device_id id; 33 33 34 - spinlock_t lock; /* protects critical sections from port's interrupt handler */ 34 + /* Protects critical sections from port's interrupt handler */ 35 + spinlock_t lock; 35 36 36 37 int (*write)(struct serio *, unsigned char); 37 38 int (*open)(struct serio *); ··· 41 40 void (*stop)(struct serio *); 42 41 43 42 struct serio *parent; 44 - struct list_head child_node; /* Entry in parent->children list */ 43 + /* Entry in parent->children list */ 44 + struct list_head child_node; 45 45 struct list_head children; 46 - unsigned int depth; /* level of nesting in serio hierarchy */ 46 + /* Level of nesting in serio hierarchy */ 47 + unsigned int depth; 47 48 48 - struct serio_driver *drv; /* accessed from interrupt, must be protected by serio->lock and serio->sem */ 49 - struct mutex drv_mutex; /* protects serio->drv so attributes can pin driver */ 49 + /* 50 + * serio->drv is accessed from interrupt handlers; when modifying 51 + * caller should acquire serio->drv_mutex and serio->lock. 52 + */ 53 + struct serio_driver *drv; 54 + /* Protects serio->drv so attributes can pin current driver */ 55 + struct mutex drv_mutex; 50 56 51 57 struct device dev; 52 58 53 59 struct list_head node; 60 + 61 + /* 62 + * For use by PS/2 layer when several ports share hardware and 63 + * may get indigestion when exposed to concurrent access (i8042). 64 + */ 65 + struct mutex *ps2_cmd_mutex; 54 66 }; 55 67 #define to_serio_port(d) container_of(d, struct serio, dev) 56 68