aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Torokhov2016-07-25 13:36:54 -0500
committerGreg Kroah-Hartman2016-09-07 01:30:00 -0500
commit930100acbd2eb700e35daa01e2091947e1ecf7e3 (patch)
tree598f8bb4f88bb7e19fb21a467fe7c89347797e48
parentfb21f6365c7bd0d6ba5d1889194be3b966f34aaf (diff)
downloadti-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.c16
-rw-r--r--drivers/input/serio/libps2.c10
-rw-r--r--include/linux/i8042.h6
-rw-r--r--include/linux/serio.h24
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 */
1327bool 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}
1337EXPORT_SYMBOL(i8042_check_port_owner);
1338
1339static void i8042_free_irqs(void) 1325static 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
57void ps2_begin_command(struct ps2dev *ps2dev) 57void 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}
64EXPORT_SYMBOL(ps2_begin_command); 63EXPORT_SYMBOL(ps2_begin_command);
65 64
66void ps2_end_command(struct ps2dev *ps2dev) 65void 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}
73EXPORT_SYMBOL(ps2_end_command); 71EXPORT_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;
62void i8042_lock_chip(void); 62void i8042_lock_chip(void);
63void i8042_unlock_chip(void); 63void i8042_unlock_chip(void);
64int i8042_command(unsigned char *param, int command); 64int i8042_command(unsigned char *param, int command);
65bool i8042_check_port_owner(const struct serio *);
66int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str, 65int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str,
67 struct serio *serio)); 66 struct serio *serio));
68int i8042_remove_filter(bool (*filter)(unsigned char data, unsigned char str, 67int 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
86static inline bool i8042_check_port_owner(const struct serio *serio)
87{
88 return false;
89}
90
91static inline int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str, 85static 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