11e8a1faeSThomas Huth /*
21e8a1faeSThomas Huth * QEMU device plug/unplug handling
31e8a1faeSThomas Huth *
41e8a1faeSThomas Huth * Copyright (C) 2019 Red Hat Inc.
51e8a1faeSThomas Huth *
61e8a1faeSThomas Huth * Authors:
71e8a1faeSThomas Huth * David Hildenbrand <david@redhat.com>
81e8a1faeSThomas Huth *
91e8a1faeSThomas Huth * This work is licensed under the terms of the GNU GPL, version 2 or later.
101e8a1faeSThomas Huth * See the COPYING file in the top-level directory.
111e8a1faeSThomas Huth */
121e8a1faeSThomas Huth
131e8a1faeSThomas Huth #include "qemu/osdep.h"
14907b5105SMarc-André Lureau #include "libqtest.h"
151e8a1faeSThomas Huth #include "qapi/qmp/qdict.h"
161e8a1faeSThomas Huth #include "qapi/qmp/qstring.h"
171e8a1faeSThomas Huth
system_reset(QTestState * qtest)181e8a1faeSThomas Huth static void system_reset(QTestState *qtest)
191e8a1faeSThomas Huth {
201e8a1faeSThomas Huth QDict *resp;
211e8a1faeSThomas Huth
221e8a1faeSThomas Huth resp = qtest_qmp(qtest, "{'execute': 'system_reset'}");
231e8a1faeSThomas Huth g_assert(qdict_haskey(resp, "return"));
241e8a1faeSThomas Huth qobject_unref(resp);
251e8a1faeSThomas Huth }
261e8a1faeSThomas Huth
wait_device_deleted_event(QTestState * qtest,const char * id)271e8a1faeSThomas Huth static void wait_device_deleted_event(QTestState *qtest, const char *id)
281e8a1faeSThomas Huth {
291e8a1faeSThomas Huth QDict *resp, *data;
301e8a1faeSThomas Huth QString *qstr;
311e8a1faeSThomas Huth
321e8a1faeSThomas Huth /*
331e8a1faeSThomas Huth * Other devices might get removed along with the removed device. Skip
341e8a1faeSThomas Huth * these. The device of interest will be the last one.
351e8a1faeSThomas Huth */
361e8a1faeSThomas Huth for (;;) {
371e8a1faeSThomas Huth resp = qtest_qmp_eventwait_ref(qtest, "DEVICE_DELETED");
381e8a1faeSThomas Huth data = qdict_get_qdict(resp, "data");
391e8a1faeSThomas Huth if (!data || !qdict_get(data, "device")) {
401e8a1faeSThomas Huth qobject_unref(resp);
411e8a1faeSThomas Huth continue;
421e8a1faeSThomas Huth }
431e8a1faeSThomas Huth qstr = qobject_to(QString, qdict_get(data, "device"));
441e8a1faeSThomas Huth g_assert(qstr);
451e8a1faeSThomas Huth if (!strcmp(qstring_get_str(qstr), id)) {
461e8a1faeSThomas Huth qobject_unref(resp);
471e8a1faeSThomas Huth break;
481e8a1faeSThomas Huth }
491e8a1faeSThomas Huth qobject_unref(resp);
501e8a1faeSThomas Huth }
511e8a1faeSThomas Huth }
521e8a1faeSThomas Huth
process_device_remove(QTestState * qtest,const char * id)539bcc0f7dSMichael Labiuk static void process_device_remove(QTestState *qtest, const char *id)
549bcc0f7dSMichael Labiuk {
559bcc0f7dSMichael Labiuk /*
569bcc0f7dSMichael Labiuk * Request device removal. As the guest is not running, the request won't
579bcc0f7dSMichael Labiuk * be processed. However during system reset, the removal will be
589bcc0f7dSMichael Labiuk * handled, removing the device.
599bcc0f7dSMichael Labiuk */
60ea42a6c4SMichael Labiuk qtest_qmp_device_del_send(qtest, id);
619bcc0f7dSMichael Labiuk system_reset(qtest);
629bcc0f7dSMichael Labiuk wait_device_deleted_event(qtest, id);
639bcc0f7dSMichael Labiuk }
649bcc0f7dSMichael Labiuk
test_pci_unplug_request(void)651e8a1faeSThomas Huth static void test_pci_unplug_request(void)
661e8a1faeSThomas Huth {
67ca7d9f5fSFabiano Rosas QTestState *qtest;
687b172333SDr. David Alan Gilbert const char *arch = qtest_get_arch();
697b172333SDr. David Alan Gilbert const char *machine_addition = "";
707b172333SDr. David Alan Gilbert
7145ec78beSFabiano Rosas if (!qtest_has_device("virtio-mouse-pci")) {
7245ec78beSFabiano Rosas g_test_skip("Device virtio-mouse-pci not available");
7345ec78beSFabiano Rosas return;
7445ec78beSFabiano Rosas }
7545ec78beSFabiano Rosas
767b172333SDr. David Alan Gilbert if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
777b172333SDr. David Alan Gilbert machine_addition = "-machine pc";
787b172333SDr. David Alan Gilbert }
797b172333SDr. David Alan Gilbert
80ca7d9f5fSFabiano Rosas qtest = qtest_initf("%s -device virtio-mouse-pci,id=dev0",
817b172333SDr. David Alan Gilbert machine_addition);
821e8a1faeSThomas Huth
839bcc0f7dSMichael Labiuk process_device_remove(qtest, "dev0");
841e8a1faeSThomas Huth
851e8a1faeSThomas Huth qtest_quit(qtest);
861e8a1faeSThomas Huth }
871e8a1faeSThomas Huth
test_q35_pci_unplug_request(void)88a12f1a7eSMichael Labiuk static void test_q35_pci_unplug_request(void)
89a12f1a7eSMichael Labiuk {
9045ec78beSFabiano Rosas QTestState *qtest;
91a12f1a7eSMichael Labiuk
9245ec78beSFabiano Rosas if (!qtest_has_device("virtio-mouse-pci")) {
9345ec78beSFabiano Rosas g_test_skip("Device virtio-mouse-pci not available");
9445ec78beSFabiano Rosas return;
9545ec78beSFabiano Rosas }
9645ec78beSFabiano Rosas
9745ec78beSFabiano Rosas qtest = qtest_initf("-machine q35 "
98a12f1a7eSMichael Labiuk "-device pcie-root-port,id=p1 "
99a12f1a7eSMichael Labiuk "-device pcie-pci-bridge,bus=p1,id=b1 "
100a12f1a7eSMichael Labiuk "-device virtio-mouse-pci,bus=b1,id=dev0");
101a12f1a7eSMichael Labiuk
102a12f1a7eSMichael Labiuk process_device_remove(qtest, "dev0");
103a12f1a7eSMichael Labiuk
104a12f1a7eSMichael Labiuk qtest_quit(qtest);
105a12f1a7eSMichael Labiuk }
106a12f1a7eSMichael Labiuk
test_pci_unplug_json_request(void)10764b4529aSDaniel P. Berrangé static void test_pci_unplug_json_request(void)
10864b4529aSDaniel P. Berrangé {
109ca7d9f5fSFabiano Rosas QTestState *qtest;
1107b172333SDr. David Alan Gilbert const char *arch = qtest_get_arch();
1117b172333SDr. David Alan Gilbert const char *machine_addition = "";
1127b172333SDr. David Alan Gilbert
11345ec78beSFabiano Rosas if (!qtest_has_device("virtio-mouse-pci")) {
11445ec78beSFabiano Rosas g_test_skip("Device virtio-mouse-pci not available");
11545ec78beSFabiano Rosas return;
11645ec78beSFabiano Rosas }
11745ec78beSFabiano Rosas
1187b172333SDr. David Alan Gilbert if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
1197b172333SDr. David Alan Gilbert machine_addition = "-machine pc";
1207b172333SDr. David Alan Gilbert }
1217b172333SDr. David Alan Gilbert
122ca7d9f5fSFabiano Rosas qtest = qtest_initf(
123fbde3ae8SBin Meng "%s -device \"{'driver': 'virtio-mouse-pci', 'id': 'dev0'}\"",
1247b172333SDr. David Alan Gilbert machine_addition);
12564b4529aSDaniel P. Berrangé
1269bcc0f7dSMichael Labiuk process_device_remove(qtest, "dev0");
12764b4529aSDaniel P. Berrangé
12864b4529aSDaniel P. Berrangé qtest_quit(qtest);
12964b4529aSDaniel P. Berrangé }
13064b4529aSDaniel P. Berrangé
test_q35_pci_unplug_json_request(void)131a12f1a7eSMichael Labiuk static void test_q35_pci_unplug_json_request(void)
132a12f1a7eSMichael Labiuk {
13345ec78beSFabiano Rosas QTestState *qtest;
134e4439e52SBin Meng const char *port = "-device \"{'driver': 'pcie-root-port', "
135e4439e52SBin Meng "'id': 'p1'}\"";
136a12f1a7eSMichael Labiuk
137e4439e52SBin Meng const char *bridge = "-device \"{'driver': 'pcie-pci-bridge', "
138e4439e52SBin Meng "'id': 'b1', "
139e4439e52SBin Meng "'bus': 'p1'}\"";
140a12f1a7eSMichael Labiuk
141e4439e52SBin Meng const char *device = "-device \"{'driver': 'virtio-mouse-pci', "
142e4439e52SBin Meng "'bus': 'b1', "
143e4439e52SBin Meng "'id': 'dev0'}\"";
144a12f1a7eSMichael Labiuk
14545ec78beSFabiano Rosas if (!qtest_has_device("virtio-mouse-pci")) {
14645ec78beSFabiano Rosas g_test_skip("Device virtio-mouse-pci not available");
14745ec78beSFabiano Rosas return;
14845ec78beSFabiano Rosas }
14945ec78beSFabiano Rosas
15045ec78beSFabiano Rosas qtest = qtest_initf("-machine q35 %s %s %s", port, bridge, device);
151a12f1a7eSMichael Labiuk
152a12f1a7eSMichael Labiuk process_device_remove(qtest, "dev0");
153a12f1a7eSMichael Labiuk
154a12f1a7eSMichael Labiuk qtest_quit(qtest);
155a12f1a7eSMichael Labiuk }
156a12f1a7eSMichael Labiuk
test_ccw_unplug(void)1571e8a1faeSThomas Huth static void test_ccw_unplug(void)
1581e8a1faeSThomas Huth {
15965331bf5SThomas Huth QTestState *qtest;
16065331bf5SThomas Huth
16165331bf5SThomas Huth if (!qtest_has_device("virtio-balloon-ccw")) {
16265331bf5SThomas Huth g_test_skip("Device virtio-balloon-ccw not available");
16365331bf5SThomas Huth return;
16465331bf5SThomas Huth }
16565331bf5SThomas Huth
16665331bf5SThomas Huth qtest = qtest_initf("-device virtio-balloon-ccw,id=dev0");
1671e8a1faeSThomas Huth
168ea42a6c4SMichael Labiuk qtest_qmp_device_del_send(qtest, "dev0");
1691e8a1faeSThomas Huth wait_device_deleted_event(qtest, "dev0");
1701e8a1faeSThomas Huth
1711e8a1faeSThomas Huth qtest_quit(qtest);
1721e8a1faeSThomas Huth }
1731e8a1faeSThomas Huth
test_spapr_cpu_unplug_request(void)1741e8a1faeSThomas Huth static void test_spapr_cpu_unplug_request(void)
1751e8a1faeSThomas Huth {
1761e8a1faeSThomas Huth QTestState *qtest;
1771e8a1faeSThomas Huth
178*277ee172SNicholas Piggin qtest = qtest_initf("-cpu power9_v2.2 -smp 1,maxcpus=2 "
179*277ee172SNicholas Piggin "-device power9_v2.2-spapr-cpu-core,core-id=1,id=dev0");
1801e8a1faeSThomas Huth
1811e8a1faeSThomas Huth /* similar to test_pci_unplug_request */
1829bcc0f7dSMichael Labiuk process_device_remove(qtest, "dev0");
1831e8a1faeSThomas Huth
1841e8a1faeSThomas Huth qtest_quit(qtest);
1851e8a1faeSThomas Huth }
1861e8a1faeSThomas Huth
test_spapr_memory_unplug_request(void)1871e8a1faeSThomas Huth static void test_spapr_memory_unplug_request(void)
1881e8a1faeSThomas Huth {
1891e8a1faeSThomas Huth QTestState *qtest;
1901e8a1faeSThomas Huth
1911e8a1faeSThomas Huth qtest = qtest_initf("-m 256M,slots=1,maxmem=768M "
1921e8a1faeSThomas Huth "-object memory-backend-ram,id=mem0,size=512M "
1931e8a1faeSThomas Huth "-device pc-dimm,id=dev0,memdev=mem0");
1941e8a1faeSThomas Huth
1951e8a1faeSThomas Huth /* similar to test_pci_unplug_request */
1969bcc0f7dSMichael Labiuk process_device_remove(qtest, "dev0");
1971e8a1faeSThomas Huth
1981e8a1faeSThomas Huth qtest_quit(qtest);
1991e8a1faeSThomas Huth }
2001e8a1faeSThomas Huth
test_spapr_phb_unplug_request(void)2011e8a1faeSThomas Huth static void test_spapr_phb_unplug_request(void)
2021e8a1faeSThomas Huth {
2031e8a1faeSThomas Huth QTestState *qtest;
2041e8a1faeSThomas Huth
2051e8a1faeSThomas Huth qtest = qtest_initf("-device spapr-pci-host-bridge,index=1,id=dev0");
2061e8a1faeSThomas Huth
2071e8a1faeSThomas Huth /* similar to test_pci_unplug_request */
2089bcc0f7dSMichael Labiuk process_device_remove(qtest, "dev0");
2091e8a1faeSThomas Huth
2101e8a1faeSThomas Huth qtest_quit(qtest);
2111e8a1faeSThomas Huth }
2121e8a1faeSThomas Huth
main(int argc,char ** argv)2131e8a1faeSThomas Huth int main(int argc, char **argv)
2141e8a1faeSThomas Huth {
2151e8a1faeSThomas Huth const char *arch = qtest_get_arch();
2161e8a1faeSThomas Huth
2171e8a1faeSThomas Huth g_test_init(&argc, &argv, NULL);
2181e8a1faeSThomas Huth
2191e8a1faeSThomas Huth /*
2201e8a1faeSThomas Huth * We need a system that will process unplug requests during system resets
2211e8a1faeSThomas Huth * and does not do PCI surprise removal. This holds for x86 ACPI,
2221e8a1faeSThomas Huth * s390x and spapr.
2231e8a1faeSThomas Huth */
2241e8a1faeSThomas Huth qtest_add_func("/device-plug/pci-unplug-request",
2251e8a1faeSThomas Huth test_pci_unplug_request);
22664b4529aSDaniel P. Berrangé qtest_add_func("/device-plug/pci-unplug-json-request",
22764b4529aSDaniel P. Berrangé test_pci_unplug_json_request);
2281e8a1faeSThomas Huth
2291e8a1faeSThomas Huth if (!strcmp(arch, "s390x")) {
2301e8a1faeSThomas Huth qtest_add_func("/device-plug/ccw-unplug",
2311e8a1faeSThomas Huth test_ccw_unplug);
2321e8a1faeSThomas Huth }
2331e8a1faeSThomas Huth
2341e8a1faeSThomas Huth if (!strcmp(arch, "ppc64")) {
2351e8a1faeSThomas Huth qtest_add_func("/device-plug/spapr-cpu-unplug-request",
2361e8a1faeSThomas Huth test_spapr_cpu_unplug_request);
2371e8a1faeSThomas Huth qtest_add_func("/device-plug/spapr-memory-unplug-request",
2381e8a1faeSThomas Huth test_spapr_memory_unplug_request);
2391e8a1faeSThomas Huth qtest_add_func("/device-plug/spapr-phb-unplug-request",
2401e8a1faeSThomas Huth test_spapr_phb_unplug_request);
2411e8a1faeSThomas Huth }
2421e8a1faeSThomas Huth
243a12f1a7eSMichael Labiuk if (!strcmp(arch, "x86_64") && qtest_has_machine("q35")) {
244a12f1a7eSMichael Labiuk qtest_add_func("/device-plug/q35-pci-unplug-request",
245a12f1a7eSMichael Labiuk test_q35_pci_unplug_request);
246a12f1a7eSMichael Labiuk qtest_add_func("/device-plug/q35-pci-unplug-json-request",
247a12f1a7eSMichael Labiuk test_q35_pci_unplug_json_request);
248a12f1a7eSMichael Labiuk }
249a12f1a7eSMichael Labiuk
2501e8a1faeSThomas Huth return g_test_run();
2511e8a1faeSThomas Huth }
252