diff options
author | Dmitry Torokhov | 2016-07-25 13:36:54 -0500 |
---|---|---|
committer | Greg Kroah-Hartman | 2016-09-07 01:30:00 -0500 |
commit | 930100acbd2eb700e35daa01e2091947e1ecf7e3 (patch) | |
tree | 598f8bb4f88bb7e19fb21a467fe7c89347797e48 | |
parent | fb21f6365c7bd0d6ba5d1889194be3b966f34aaf (diff) | |
download | ti-linux-kernel-930100acbd2eb700e35daa01e2091947e1ecf7e3.tar.gz ti-linux-kernel-930100acbd2eb700e35daa01e2091947e1ecf7e3.tar.xz ti-linux-kernel-930100acbd2eb700e35daa01e2091947e1ecf7e3.zip |
Input: i8042 - break load dependency between atkbd/psmouse and i8042
commit 4097461897df91041382ff6fcd2bfa7ee6b2448c upstream.
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>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/input/serio/i8042.c | 16 | ||||
-rw-r--r-- | drivers/input/serio/libps2.c | 10 | ||||
-rw-r--r-- | include/linux/i8042.h | 6 | ||||
-rw-r--r-- | 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 eb796fff9e62..3ff3d0e3c9c6 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) | |||
1230 | serio->start = i8042_start; | 1230 | serio->start = i8042_start; |
1231 | serio->stop = i8042_stop; | 1231 | serio->stop = i8042_stop; |
1232 | serio->close = i8042_port_close; | 1232 | serio->close = i8042_port_close; |
1233 | serio->ps2_cmd_mutex = &i8042_mutex; | ||
1233 | serio->port_data = port; | 1234 | serio->port_data = port; |
1234 | serio->dev.parent = &i8042_platform_device->dev; | 1235 | serio->dev.parent = &i8042_platform_device->dev; |
1235 | strlcpy(serio->name, "i8042 KBD port", sizeof(serio->name)); | 1236 | strlcpy(serio->name, "i8042 KBD port", sizeof(serio->name)); |
@@ -1321,21 +1322,6 @@ static void i8042_unregister_ports(void) | |||
1321 | } | 1322 | } |
1322 | } | 1323 | } |
1323 | 1324 | ||
1324 | /* | ||
1325 | * Checks whether port belongs to i8042 controller. | ||
1326 | */ | ||
1327 | bool i8042_check_port_owner(const struct serio *port) | ||
1328 | { | ||
1329 | int i; | ||
1330 | |||
1331 | for (i = 0; i < I8042_NUM_PORTS; i++) | ||
1332 | if (i8042_ports[i].serio == port) | ||
1333 | return true; | ||
1334 | |||
1335 | return false; | ||
1336 | } | ||
1337 | EXPORT_SYMBOL(i8042_check_port_owner); | ||
1338 | |||
1339 | static void i8042_free_irqs(void) | 1325 | static void i8042_free_irqs(void) |
1340 | { | 1326 | { |
1341 | if (i8042_aux_irq_registered) | 1327 | if (i8042_aux_irq_registered) |
diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c index 75516996db20..ded0c6f65c9f 100644 --- a/drivers/input/serio/libps2.c +++ b/drivers/input/serio/libps2.c | |||
@@ -56,19 +56,17 @@ EXPORT_SYMBOL(ps2_sendbyte); | |||
56 | 56 | ||
57 | void ps2_begin_command(struct ps2dev *ps2dev) | 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)) | 61 | mutex_lock(m); |
62 | i8042_lock_chip(); | ||
63 | } | 62 | } |
64 | EXPORT_SYMBOL(ps2_begin_command); | 63 | EXPORT_SYMBOL(ps2_begin_command); |
65 | 64 | ||
66 | void ps2_end_command(struct ps2dev *ps2dev) | 65 | void ps2_end_command(struct ps2dev *ps2dev) |
67 | { | 66 | { |
68 | if (i8042_check_port_owner(ps2dev->serio)) | 67 | struct mutex *m = ps2dev->serio->ps2_cmd_mutex ?: &ps2dev->cmd_mutex; |
69 | i8042_unlock_chip(); | ||
70 | 68 | ||
71 | mutex_unlock(&ps2dev->cmd_mutex); | 69 | mutex_unlock(m); |
72 | } | 70 | } |
73 | EXPORT_SYMBOL(ps2_end_command); | 71 | EXPORT_SYMBOL(ps2_end_command); |
74 | 72 | ||
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; | |||
62 | void i8042_lock_chip(void); | 62 | void i8042_lock_chip(void); |
63 | void i8042_unlock_chip(void); | 63 | void i8042_unlock_chip(void); |
64 | int i8042_command(unsigned char *param, int command); | 64 | int i8042_command(unsigned char *param, int command); |
65 | bool i8042_check_port_owner(const struct serio *); | ||
66 | int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str, | 65 | int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str, |
67 | struct serio *serio)); | 66 | struct serio *serio)); |
68 | int i8042_remove_filter(bool (*filter)(unsigned char data, unsigned char str, | 67 | 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) | |||
83 | return -ENODEV; | 82 | return -ENODEV; |
84 | } | 83 | } |
85 | 84 | ||
86 | static inline bool i8042_check_port_owner(const struct serio *serio) | ||
87 | { | ||
88 | return false; | ||
89 | } | ||
90 | |||
91 | static inline int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str, | 85 | static inline int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str, |
92 | struct serio *serio)) | 86 | struct serio *serio)) |
93 | { | 87 | { |
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 { | |||
29 | 29 | ||
30 | struct serio_device_id id; | 30 | struct serio_device_id id; |
31 | 31 | ||
32 | spinlock_t lock; /* protects critical sections from port's interrupt handler */ | 32 | /* Protects critical sections from port's interrupt handler */ |
33 | spinlock_t lock; | ||
33 | 34 | ||
34 | int (*write)(struct serio *, unsigned char); | 35 | int (*write)(struct serio *, unsigned char); |
35 | int (*open)(struct serio *); | 36 | int (*open)(struct serio *); |
@@ -38,16 +39,29 @@ struct serio { | |||
38 | void (*stop)(struct serio *); | 39 | void (*stop)(struct serio *); |
39 | 40 | ||
40 | struct serio *parent; | 41 | struct serio *parent; |
41 | struct list_head child_node; /* Entry in parent->children list */ | 42 | /* Entry in parent->children list */ |
43 | struct list_head child_node; | ||
42 | struct list_head children; | 44 | struct list_head children; |
43 | unsigned int depth; /* level of nesting in serio hierarchy */ | 45 | /* Level of nesting in serio hierarchy */ |
46 | unsigned int depth; | ||
44 | 47 | ||
45 | struct serio_driver *drv; /* accessed from interrupt, must be protected by serio->lock and serio->sem */ | 48 | /* |
46 | struct mutex drv_mutex; /* protects serio->drv so attributes can pin driver */ | 49 | * serio->drv is accessed from interrupt handlers; when modifying |
50 | * caller should acquire serio->drv_mutex and serio->lock. | ||
51 | */ | ||
52 | struct serio_driver *drv; | ||
53 | /* Protects serio->drv so attributes can pin current driver */ | ||
54 | struct mutex drv_mutex; | ||
47 | 55 | ||
48 | struct device dev; | 56 | struct device dev; |
49 | 57 | ||
50 | struct list_head node; | 58 | struct list_head node; |
59 | |||
60 | /* | ||
61 | * For use by PS/2 layer when several ports share hardware and | ||
62 | * may get indigestion when exposed to concurrent access (i8042). | ||
63 | */ | ||
64 | struct mutex *ps2_cmd_mutex; | ||
51 | }; | 65 | }; |
52 | #define to_serio_port(d) container_of(d, struct serio, dev) | 66 | #define to_serio_port(d) container_of(d, struct serio, dev) |
53 | 67 | ||