From: Christian Quante <[email protected]> ps2_write_mouse() ends its command switch with a bare "default: break;", so an unknown command draws no reply at all. A real PS/2 device answers every byte it is given -- ACK (0xFA) when it understood one, resend (0xFE) when it did not -- and a guest that gets nothing back is left waiting out its reply timeout. The keyboard path in the same file has answered unknown commands with KBD_REPLY_RESEND since commit 06b3611fc2a3 ("ps2: reject unknown commands, instead of blindly accepting them").
Two guests were measured on this. OS/2 probes the mouse with the vendor command 0xBB, which QEMU does not implement, and then polls the status port until its own timeout runs out. On a Warp 3 guest that wait costs about 25 ms of every boot under TCG, and 2.1 s under KVM, where each of those polls leaves the guest. With this patch the wait ends on the first read: the guest takes the same error path an unexpected reply would, and does not retry. Linux runs into two of them while probing the mouse: the ALPS probe sends 0xEC (reset wrap mode), which ps2_write_mouse() only answers while the mouse is in wrap mode, and the TrackPoint probe sends 0xE1. Each costs libps2 a 200 ms reply timeout. Timing the psmouse detection from a mark written to /dev/kmsg to the kernel's "input:" line, three boots each of a 6.18.35 kernel under TCG: 426.7/428.8/441.6 ms without this patch, 21.4/21.6/21.2 ms with it. The mouse is detected identically either way; only the error the probe ends in changes, from -EIO (nothing came back at all) to -EPROTO (libps2 gives up after its second attempt). The specification's second stage -- 0xFC (Error) when the byte after a rejected one is invalid as well -- is deliberately left out. It would need state that has to survive migration, no guest is known to test for it, and the keyboard path does without it as well. Cc: [email protected] Signed-off-by: Christian Quante <[email protected]> Reviewed-by: Marc-André Lureau <[email protected]> Reviewed-by: Akihiko Odaki <[email protected]> Message-ID: <[email protected]> (cherry picked from commit 0846740652d1333369265fa075708b5a386c5ff6) Signed-off-by: Michael Tokarev <[email protected]> diff --git a/hw/input/ps2.c b/hw/input/ps2.c index 6a41b024c80..68e42982031 100644 --- a/hw/input/ps2.c +++ b/hw/input/ps2.c @@ -72,6 +72,7 @@ #define AUX_SET_DEFAULT 0xF6 #define AUX_RESET 0xFF /* Reset aux device */ #define AUX_ACK 0xFA /* Command byte ACK. */ +#define AUX_RESEND 0xFE /* Command NACK, send the cmd again */ #define MOUSE_STATUS_REMOTE 0x40 #define MOUSE_STATUS_ENABLED 0x20 @@ -961,6 +962,11 @@ void ps2_write_mouse(PS2MouseState *s, int val) s->mouse_type); break; default: + /* + * A PS/2 device answers every command it is given; an unknown + * one draws a resend. + */ + ps2_queue(ps2, AUX_RESEND); break; } break; -- 2.47.3
