Skip to content

Commit 4097461

Browse files
committed
Input: i8042 - break load dependency between atkbd/psmouse and i8042
As explained in [email protected] 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 <[email protected]> Tested-by: Mark Laws <[email protected]> Cc: [email protected] Signed-off-by: Dmitry Torokhov <[email protected]>
1 parent 887ec0b commit 4097461

File tree

4 files changed

+24
-32
lines changed

4 files changed

+24
-32
lines changed

drivers/input/serio/i8042.c

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1277,6 +1277,7 @@ static int __init i8042_create_kbd_port(void)
12771277
serio->start = i8042_start;
12781278
serio->stop = i8042_stop;
12791279
serio->close = i8042_port_close;
1280+
serio->ps2_cmd_mutex = &i8042_mutex;
12801281
serio->port_data = port;
12811282
serio->dev.parent = &i8042_platform_device->dev;
12821283
strlcpy(serio->name, "i8042 KBD port", sizeof(serio->name));
@@ -1373,21 +1374,6 @@ static void i8042_unregister_ports(void)
13731374
}
13741375
}
13751376

1376-
/*
1377-
* Checks whether port belongs to i8042 controller.
1378-
*/
1379-
bool i8042_check_port_owner(const struct serio *port)
1380-
{
1381-
int i;
1382-
1383-
for (i = 0; i < I8042_NUM_PORTS; i++)
1384-
if (i8042_ports[i].serio == port)
1385-
return true;
1386-
1387-
return false;
1388-
}
1389-
EXPORT_SYMBOL(i8042_check_port_owner);
1390-
13911377
static void i8042_free_irqs(void)
13921378
{
13931379
if (i8042_aux_irq_registered)

drivers/input/serio/libps2.c

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,19 +56,17 @@ EXPORT_SYMBOL(ps2_sendbyte);
5656

5757
void ps2_begin_command(struct ps2dev *ps2dev)
5858
{
59-
mutex_lock(&ps2dev->cmd_mutex);
59+
struct mutex *m = ps2dev->serio->ps2_cmd_mutex ?: &ps2dev->cmd_mutex;
6060

61-
if (i8042_check_port_owner(ps2dev->serio))
62-
i8042_lock_chip();
61+
mutex_lock(m);
6362
}
6463
EXPORT_SYMBOL(ps2_begin_command);
6564

6665
void ps2_end_command(struct ps2dev *ps2dev)
6766
{
68-
if (i8042_check_port_owner(ps2dev->serio))
69-
i8042_unlock_chip();
67+
struct mutex *m = ps2dev->serio->ps2_cmd_mutex ?: &ps2dev->cmd_mutex;
7068

71-
mutex_unlock(&ps2dev->cmd_mutex);
69+
mutex_unlock(m);
7270
}
7371
EXPORT_SYMBOL(ps2_end_command);
7472

include/linux/i8042.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ struct serio;
6262
void i8042_lock_chip(void);
6363
void i8042_unlock_chip(void);
6464
int i8042_command(unsigned char *param, int command);
65-
bool i8042_check_port_owner(const struct serio *);
6665
int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str,
6766
struct serio *serio));
6867
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)
8382
return -ENODEV;
8483
}
8584

86-
static inline bool i8042_check_port_owner(const struct serio *serio)
87-
{
88-
return false;
89-
}
90-
9185
static inline int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str,
9286
struct serio *serio))
9387
{

include/linux/serio.h

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ struct serio {
3131

3232
struct serio_device_id id;
3333

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;
3536

3637
int (*write)(struct serio *, unsigned char);
3738
int (*open)(struct serio *);
@@ -40,16 +41,29 @@ struct serio {
4041
void (*stop)(struct serio *);
4142

4243
struct serio *parent;
43-
struct list_head child_node; /* Entry in parent->children list */
44+
/* Entry in parent->children list */
45+
struct list_head child_node;
4446
struct list_head children;
45-
unsigned int depth; /* level of nesting in serio hierarchy */
47+
/* Level of nesting in serio hierarchy */
48+
unsigned int depth;
4649

47-
struct serio_driver *drv; /* accessed from interrupt, must be protected by serio->lock and serio->sem */
48-
struct mutex drv_mutex; /* protects serio->drv so attributes can pin driver */
50+
/*
51+
* serio->drv is accessed from interrupt handlers; when modifying
52+
* caller should acquire serio->drv_mutex and serio->lock.
53+
*/
54+
struct serio_driver *drv;
55+
/* Protects serio->drv so attributes can pin current driver */
56+
struct mutex drv_mutex;
4957

5058
struct device dev;
5159

5260
struct list_head node;
61+
62+
/*
63+
* For use by PS/2 layer when several ports share hardware and
64+
* may get indigestion when exposed to concurrent access (i8042).
65+
*/
66+
struct mutex *ps2_cmd_mutex;
5367
};
5468
#define to_serio_port(d) container_of(d, struct serio, dev)
5569

0 commit comments

Comments
 (0)