master
c 134 lines 3.97 KB
Raw
1 /*
2 * QTest testcase for USB xHCI controller
3 *
4 * Copyright (c) 2014 HUAWEI TECHNOLOGIES CO., LTD.
5 *
6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
7 * See the COPYING file in the top-level directory.
8 */
9
10 #include "qemu/osdep.h"
11 #include "libqtest-single.h"
12 #include "libqos/usb.h"
13 #include "qobject/qdict.h"
14
15 static void wait_device_deleted_event(QTestState *qtest, const char *id)
16 {
17 QDict *resp, *data;
18 const char *device;
19
20 /*
21 * Other devices might get removed along with the removed device. Skip
22 * these. The device of interest will be the last one.
23 */
24 for (;;) {
25 resp = qtest_qmp_eventwait_ref(qtest, "DEVICE_DELETED");
26 data = qdict_get_qdict(resp, "data");
27 device = data ? qdict_get_try_str(data, "device") : NULL;
28 if (device && !strcmp(device, id)) {
29 qobject_unref(resp);
30 break;
31 }
32 qobject_unref(resp);
33 }
34 }
35
36 /*
37 * Regression test for the xHCI-PCI "host" strong-link reference cycle.
38 *
39 * The xHCI PCI wrapper embeds an xhci-core child whose strong "host" link
40 * points back at the PCI device, forming a refcount cycle. If
41 * usb_xhci_pci_exit() does not break that cycle, the device's refcount never
42 * reaches 0 on unplug, device_finalize() never runs, and therefore the
43 * DEVICE_DELETED event (emitted from device_finalize()) is never sent.
44 *
45 * This test hot-plugs an xHCI controller into an ACPI-hotpluggable bus,
46 * requests its removal and waits for DEVICE_DELETED. Without the fix the event
47 * is never delivered (device_finalize() is blocked), so the test would
48 * hang/time out.
49 */
50 static void test_xhci_unplug_finalize(void)
51 {
52 QTestState *qtest;
53 const char *arch = qtest_get_arch();
54
55 if (strcmp(arch, "i386") != 0 && strcmp(arch, "x86_64") != 0) {
56 g_test_skip("Test only runs on x86 (ACPI PCI hotplug)");
57 return;
58 }
59 if (!qtest_has_device("nec-usb-xhci")) {
60 g_test_skip("Device nec-usb-xhci not available");
61 return;
62 }
63
64 qtest = qtest_initf("-machine pc");
65
66 qtest_qmp_device_add(qtest, "nec-usb-xhci", "xhci-finalize", "{}");
67
68 /*
69 * Request device removal. As the guest is not running, the unplug request
70 * won't be processed until the next system reset, which performs the
71 * removal and triggers device_finalize() (and thus DEVICE_DELETED).
72 */
73 qtest_qmp_device_del_send(qtest, "xhci-finalize");
74 qtest_system_reset_nowait(qtest);
75 wait_device_deleted_event(qtest, "xhci-finalize");
76
77 qtest_quit(qtest);
78 }
79
80 static void test_xhci_hotplug(void)
81 {
82 usb_test_hotplug(global_qtest, "xhci", "1", NULL);
83 }
84
85 static void test_usb_uas_hotplug(void)
86 {
87 QTestState *qts = global_qtest;
88
89 qtest_qmp_device_add(qts, "usb-uas", "uas", "{}");
90 qtest_qmp_device_add(qts, "scsi-hd", "scsihd", "{'drive': 'drive0'}");
91
92 /* TODO:
93 UAS HBA driver in libqos, to check that
94 added disk is visible after BUS rescan
95 */
96
97 qtest_qmp_device_del(qts, "scsihd");
98 qtest_qmp_device_del(qts, "uas");
99 }
100
101 static void test_usb_ccid_hotplug(void)
102 {
103 QTestState *qts = global_qtest;
104
105 qtest_qmp_device_add(qts, "usb-ccid", "ccid", "{}");
106 qtest_qmp_device_del(qts, "ccid");
107 /* check the device can be added again */
108 qtest_qmp_device_add(qts, "usb-ccid", "ccid", "{}");
109 qtest_qmp_device_del(qts, "ccid");
110 }
111
112 int main(int argc, char **argv)
113 {
114 int ret;
115
116 g_test_init(&argc, &argv, NULL);
117
118 qtest_add_func("/xhci/pci/hotplug", test_xhci_hotplug);
119 qtest_add_func("/xhci/pci/unplug/finalize", test_xhci_unplug_finalize);
120 if (qtest_has_device("usb-uas")) {
121 qtest_add_func("/xhci/pci/hotplug/usb-uas", test_usb_uas_hotplug);
122 }
123 if (qtest_has_device("usb-ccid")) {
124 qtest_add_func("/xhci/pci/hotplug/usb-ccid", test_usb_ccid_hotplug);
125 }
126
127 qtest_start("-device nec-usb-xhci,id=xhci"
128 " -drive id=drive0,if=none,file=null-co://,"
129 "file.read-zeroes=on,format=raw");
130 ret = g_test_run();
131 qtest_end();
132
133 return ret;
134 }