17fe55c3cSAndreas Färber /* 2152e0393SThomas Huth * QTest testcase for CPU plugging 37fe55c3cSAndreas Färber * 47fe55c3cSAndreas Färber * Copyright (c) 2015 SUSE Linux GmbH 57fe55c3cSAndreas Färber * 67fe55c3cSAndreas Färber * This work is licensed under the terms of the GNU GPL, version 2 or later. 77fe55c3cSAndreas Färber * See the COPYING file in the top-level directory. 87fe55c3cSAndreas Färber */ 97fe55c3cSAndreas Färber 10681c28a3SPeter Maydell #include "qemu/osdep.h" 117fe55c3cSAndreas Färber 127fe55c3cSAndreas Färber #include "qemu-common.h" 13dd210749SThomas Huth #include "libqtest-single.h" 14452fcdbcSMarkus Armbruster #include "qapi/qmp/qdict.h" 15021a007eSIgor Mammedov #include "qapi/qmp/qlist.h" 167fe55c3cSAndreas Färber 17152e0393SThomas Huth struct PlugTestData { 1834e46f60SMarc-André Lureau char *machine; 197fe55c3cSAndreas Färber const char *cpu_model; 2080b8c0beSThomas Huth char *device_model; 217fe55c3cSAndreas Färber unsigned sockets; 227fe55c3cSAndreas Färber unsigned cores; 237fe55c3cSAndreas Färber unsigned threads; 247fe55c3cSAndreas Färber unsigned maxcpus; 257fe55c3cSAndreas Färber }; 26152e0393SThomas Huth typedef struct PlugTestData PlugTestData; 277fe55c3cSAndreas Färber 28152e0393SThomas Huth static void test_plug_with_cpu_add(gconstpointer data) 297fe55c3cSAndreas Färber { 30152e0393SThomas Huth const PlugTestData *s = data; 317fe55c3cSAndreas Färber char *args; 327fe55c3cSAndreas Färber QDict *response; 337fe55c3cSAndreas Färber unsigned int i; 347fe55c3cSAndreas Färber 357fe55c3cSAndreas Färber args = g_strdup_printf("-machine %s -cpu %s " 36bc1fb850SIgor Mammedov "-smp 1,sockets=%u,cores=%u,threads=%u,maxcpus=%u", 377fe55c3cSAndreas Färber s->machine, s->cpu_model, 387fe55c3cSAndreas Färber s->sockets, s->cores, s->threads, s->maxcpus); 397fe55c3cSAndreas Färber qtest_start(args); 407fe55c3cSAndreas Färber 41bc1fb850SIgor Mammedov for (i = 1; i < s->maxcpus; i++) { 427fe55c3cSAndreas Färber response = qmp("{ 'execute': 'cpu-add'," 437fe55c3cSAndreas Färber " 'arguments': { 'id': %d } }", i); 447fe55c3cSAndreas Färber g_assert(response); 457fe55c3cSAndreas Färber g_assert(!qdict_haskey(response, "error")); 46cb3e7f08SMarc-André Lureau qobject_unref(response); 477fe55c3cSAndreas Färber } 487fe55c3cSAndreas Färber 497fe55c3cSAndreas Färber qtest_end(); 507fe55c3cSAndreas Färber g_free(args); 517fe55c3cSAndreas Färber } 527fe55c3cSAndreas Färber 53152e0393SThomas Huth static void test_plug_without_cpu_add(gconstpointer data) 547fe55c3cSAndreas Färber { 55152e0393SThomas Huth const PlugTestData *s = data; 567fe55c3cSAndreas Färber char *args; 577fe55c3cSAndreas Färber QDict *response; 587fe55c3cSAndreas Färber 597fe55c3cSAndreas Färber args = g_strdup_printf("-machine %s -cpu %s " 60bc1fb850SIgor Mammedov "-smp 1,sockets=%u,cores=%u,threads=%u,maxcpus=%u", 617fe55c3cSAndreas Färber s->machine, s->cpu_model, 627fe55c3cSAndreas Färber s->sockets, s->cores, s->threads, s->maxcpus); 637fe55c3cSAndreas Färber qtest_start(args); 647fe55c3cSAndreas Färber 657fe55c3cSAndreas Färber response = qmp("{ 'execute': 'cpu-add'," 667fe55c3cSAndreas Färber " 'arguments': { 'id': %d } }", 677fe55c3cSAndreas Färber s->sockets * s->cores * s->threads); 687fe55c3cSAndreas Färber g_assert(response); 697fe55c3cSAndreas Färber g_assert(qdict_haskey(response, "error")); 70cb3e7f08SMarc-André Lureau qobject_unref(response); 717fe55c3cSAndreas Färber 727fe55c3cSAndreas Färber qtest_end(); 737fe55c3cSAndreas Färber g_free(args); 747fe55c3cSAndreas Färber } 757fe55c3cSAndreas Färber 76021a007eSIgor Mammedov static void test_plug_with_device_add(gconstpointer data) 7780b8c0beSThomas Huth { 7880b8c0beSThomas Huth const PlugTestData *td = data; 7980b8c0beSThomas Huth char *args; 80e5758de4SThomas Huth QTestState *qts; 81021a007eSIgor Mammedov QDict *resp; 82021a007eSIgor Mammedov QList *cpus; 83021a007eSIgor Mammedov QObject *e; 84021a007eSIgor Mammedov int hotplugged = 0; 8580b8c0beSThomas Huth 8680b8c0beSThomas Huth args = g_strdup_printf("-machine %s -cpu %s " 87bc1fb850SIgor Mammedov "-smp 1,sockets=%u,cores=%u,threads=%u,maxcpus=%u", 8880b8c0beSThomas Huth td->machine, td->cpu_model, 8980b8c0beSThomas Huth td->sockets, td->cores, td->threads, td->maxcpus); 90e5758de4SThomas Huth qts = qtest_init(args); 9180b8c0beSThomas Huth 92021a007eSIgor Mammedov resp = qtest_qmp(qts, "{ 'execute': 'query-hotpluggable-cpus'}"); 93021a007eSIgor Mammedov g_assert(qdict_haskey(resp, "return")); 94021a007eSIgor Mammedov cpus = qdict_get_qlist(resp, "return"); 95021a007eSIgor Mammedov g_assert(cpus); 96021a007eSIgor Mammedov 97021a007eSIgor Mammedov while ((e = qlist_pop(cpus))) { 98021a007eSIgor Mammedov const QDict *cpu, *props; 99021a007eSIgor Mammedov 100021a007eSIgor Mammedov cpu = qobject_to(QDict, e); 101021a007eSIgor Mammedov if (qdict_haskey(cpu, "qom-path")) { 102*74130913SMarc-André Lureau qobject_unref(e); 103021a007eSIgor Mammedov continue; 10480b8c0beSThomas Huth } 10580b8c0beSThomas Huth 106021a007eSIgor Mammedov g_assert(qdict_haskey(cpu, "props")); 107021a007eSIgor Mammedov props = qdict_get_qdict(cpu, "props"); 108021a007eSIgor Mammedov 109021a007eSIgor Mammedov qtest_qmp_device_add_qdict(qts, td->device_model, props); 110021a007eSIgor Mammedov hotplugged++; 111*74130913SMarc-André Lureau qobject_unref(e); 11280b8c0beSThomas Huth } 11380b8c0beSThomas Huth 114021a007eSIgor Mammedov /* make sure that there were hotplugged CPUs */ 115021a007eSIgor Mammedov g_assert(hotplugged); 116021a007eSIgor Mammedov qobject_unref(resp); 117e5758de4SThomas Huth qtest_quit(qts); 11873a7d31eSThomas Huth g_free(args); 11973a7d31eSThomas Huth } 12073a7d31eSThomas Huth 12134e46f60SMarc-André Lureau static void test_data_free(gpointer data) 12234e46f60SMarc-André Lureau { 123152e0393SThomas Huth PlugTestData *pc = data; 12434e46f60SMarc-André Lureau 12534e46f60SMarc-André Lureau g_free(pc->machine); 12680b8c0beSThomas Huth g_free(pc->device_model); 12734e46f60SMarc-André Lureau g_free(pc); 12834e46f60SMarc-André Lureau } 12934e46f60SMarc-André Lureau 13002ef6e87SThomas Huth static void add_pc_test_case(const char *mname) 1317fe55c3cSAndreas Färber { 13234e46f60SMarc-André Lureau char *path; 133152e0393SThomas Huth PlugTestData *data; 1347fe55c3cSAndreas Färber 1357fe55c3cSAndreas Färber if (!g_str_has_prefix(mname, "pc-")) { 13602ef6e87SThomas Huth return; 1377fe55c3cSAndreas Färber } 138152e0393SThomas Huth data = g_new(PlugTestData, 1); 13934e46f60SMarc-André Lureau data->machine = g_strdup(mname); 1407fe55c3cSAndreas Färber data->cpu_model = "Haswell"; /* 1.3+ theoretically */ 14180b8c0beSThomas Huth data->device_model = g_strdup_printf("%s-%s-cpu", data->cpu_model, 14280b8c0beSThomas Huth qtest_get_arch()); 1437fe55c3cSAndreas Färber data->sockets = 1; 1447fe55c3cSAndreas Färber data->cores = 3; 1457fe55c3cSAndreas Färber data->threads = 2; 146bc1fb850SIgor Mammedov data->maxcpus = data->sockets * data->cores * data->threads; 1477fe55c3cSAndreas Färber if (g_str_has_suffix(mname, "-1.4") || 1487fe55c3cSAndreas Färber (strcmp(mname, "pc-1.3") == 0) || 1497fe55c3cSAndreas Färber (strcmp(mname, "pc-1.2") == 0) || 1507fe55c3cSAndreas Färber (strcmp(mname, "pc-1.1") == 0) || 1517fe55c3cSAndreas Färber (strcmp(mname, "pc-1.0") == 0) || 1527fe55c3cSAndreas Färber (strcmp(mname, "pc-0.15") == 0) || 1537fe55c3cSAndreas Färber (strcmp(mname, "pc-0.14") == 0) || 1547fe55c3cSAndreas Färber (strcmp(mname, "pc-0.13") == 0) || 155cc425b5dSThomas Huth (strcmp(mname, "pc-0.12") == 0)) { 15680b8c0beSThomas Huth path = g_strdup_printf("cpu-plug/%s/init/%ux%ux%u&maxcpus=%u", 15753f77e45SAndreas Färber mname, data->sockets, data->cores, 1587fe55c3cSAndreas Färber data->threads, data->maxcpus); 159152e0393SThomas Huth qtest_add_data_func_full(path, data, test_plug_without_cpu_add, 16034e46f60SMarc-André Lureau test_data_free); 16134e46f60SMarc-André Lureau g_free(path); 1627fe55c3cSAndreas Färber } else { 16380b8c0beSThomas Huth PlugTestData *data2 = g_memdup(data, sizeof(PlugTestData)); 16480b8c0beSThomas Huth 16580b8c0beSThomas Huth data2->machine = g_strdup(data->machine); 16680b8c0beSThomas Huth data2->device_model = g_strdup(data->device_model); 16780b8c0beSThomas Huth 16880b8c0beSThomas Huth path = g_strdup_printf("cpu-plug/%s/cpu-add/%ux%ux%u&maxcpus=%u", 16953f77e45SAndreas Färber mname, data->sockets, data->cores, 1707fe55c3cSAndreas Färber data->threads, data->maxcpus); 171152e0393SThomas Huth qtest_add_data_func_full(path, data, test_plug_with_cpu_add, 17234e46f60SMarc-André Lureau test_data_free); 17334e46f60SMarc-André Lureau g_free(path); 17480b8c0beSThomas Huth path = g_strdup_printf("cpu-plug/%s/device-add/%ux%ux%u&maxcpus=%u", 17580b8c0beSThomas Huth mname, data2->sockets, data2->cores, 17680b8c0beSThomas Huth data2->threads, data2->maxcpus); 177021a007eSIgor Mammedov qtest_add_data_func_full(path, data2, test_plug_with_device_add, 17880b8c0beSThomas Huth test_data_free); 17980b8c0beSThomas Huth g_free(path); 1807fe55c3cSAndreas Färber } 1817fe55c3cSAndreas Färber } 1827fe55c3cSAndreas Färber 18373a7d31eSThomas Huth static void add_pseries_test_case(const char *mname) 18473a7d31eSThomas Huth { 18573a7d31eSThomas Huth char *path; 18673a7d31eSThomas Huth PlugTestData *data; 18773a7d31eSThomas Huth 18873a7d31eSThomas Huth if (!g_str_has_prefix(mname, "pseries-") || 18973a7d31eSThomas Huth (g_str_has_prefix(mname, "pseries-2.") && atoi(&mname[10]) < 7)) { 19073a7d31eSThomas Huth return; 19173a7d31eSThomas Huth } 19273a7d31eSThomas Huth data = g_new(PlugTestData, 1); 19373a7d31eSThomas Huth data->machine = g_strdup(mname); 19473a7d31eSThomas Huth data->cpu_model = "power8_v2.0"; 19573a7d31eSThomas Huth data->device_model = g_strdup("power8_v2.0-spapr-cpu-core"); 19673a7d31eSThomas Huth data->sockets = 2; 19773a7d31eSThomas Huth data->cores = 3; 19873a7d31eSThomas Huth data->threads = 1; 199bc1fb850SIgor Mammedov data->maxcpus = data->sockets * data->cores * data->threads; 20073a7d31eSThomas Huth 20173a7d31eSThomas Huth path = g_strdup_printf("cpu-plug/%s/device-add/%ux%ux%u&maxcpus=%u", 20273a7d31eSThomas Huth mname, data->sockets, data->cores, 20373a7d31eSThomas Huth data->threads, data->maxcpus); 204021a007eSIgor Mammedov qtest_add_data_func_full(path, data, test_plug_with_device_add, 20573a7d31eSThomas Huth test_data_free); 20673a7d31eSThomas Huth g_free(path); 20773a7d31eSThomas Huth } 20873a7d31eSThomas Huth 2097d8b00faSThomas Huth static void add_s390x_test_case(const char *mname) 2107d8b00faSThomas Huth { 2117d8b00faSThomas Huth char *path; 2127d8b00faSThomas Huth PlugTestData *data, *data2; 2137d8b00faSThomas Huth 2147d8b00faSThomas Huth if (!g_str_has_prefix(mname, "s390-ccw-virtio-")) { 2157d8b00faSThomas Huth return; 2167d8b00faSThomas Huth } 2177d8b00faSThomas Huth 2187d8b00faSThomas Huth data = g_new(PlugTestData, 1); 2197d8b00faSThomas Huth data->machine = g_strdup(mname); 2207d8b00faSThomas Huth data->cpu_model = "qemu"; 2217d8b00faSThomas Huth data->device_model = g_strdup("qemu-s390x-cpu"); 2227d8b00faSThomas Huth data->sockets = 1; 2237d8b00faSThomas Huth data->cores = 3; 2247d8b00faSThomas Huth data->threads = 1; 225bc1fb850SIgor Mammedov data->maxcpus = data->sockets * data->cores * data->threads; 2267d8b00faSThomas Huth 2277d8b00faSThomas Huth data2 = g_memdup(data, sizeof(PlugTestData)); 2287d8b00faSThomas Huth data2->machine = g_strdup(data->machine); 2297d8b00faSThomas Huth data2->device_model = g_strdup(data->device_model); 2307d8b00faSThomas Huth 2317d8b00faSThomas Huth path = g_strdup_printf("cpu-plug/%s/cpu-add/%ux%ux%u&maxcpus=%u", 2327d8b00faSThomas Huth mname, data->sockets, data->cores, 2337d8b00faSThomas Huth data->threads, data->maxcpus); 2347d8b00faSThomas Huth qtest_add_data_func_full(path, data, test_plug_with_cpu_add, 2357d8b00faSThomas Huth test_data_free); 2367d8b00faSThomas Huth g_free(path); 2377d8b00faSThomas Huth 2387d8b00faSThomas Huth path = g_strdup_printf("cpu-plug/%s/device-add/%ux%ux%u&maxcpus=%u", 2397d8b00faSThomas Huth mname, data2->sockets, data2->cores, 2407d8b00faSThomas Huth data2->threads, data2->maxcpus); 241021a007eSIgor Mammedov qtest_add_data_func_full(path, data2, test_plug_with_device_add, 2427d8b00faSThomas Huth test_data_free); 2437d8b00faSThomas Huth g_free(path); 2447d8b00faSThomas Huth } 2457d8b00faSThomas Huth 2467fe55c3cSAndreas Färber int main(int argc, char **argv) 2477fe55c3cSAndreas Färber { 2487fe55c3cSAndreas Färber const char *arch = qtest_get_arch(); 2497fe55c3cSAndreas Färber 2507fe55c3cSAndreas Färber g_test_init(&argc, &argv, NULL); 2517fe55c3cSAndreas Färber 2527fe55c3cSAndreas Färber if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { 2531f4a0d81SThomas Huth qtest_cb_for_every_machine(add_pc_test_case, g_test_quick()); 25473a7d31eSThomas Huth } else if (g_str_equal(arch, "ppc64")) { 2551f4a0d81SThomas Huth qtest_cb_for_every_machine(add_pseries_test_case, g_test_quick()); 2567d8b00faSThomas Huth } else if (g_str_equal(arch, "s390x")) { 2571f4a0d81SThomas Huth qtest_cb_for_every_machine(add_s390x_test_case, g_test_quick()); 2587fe55c3cSAndreas Färber } 2597fe55c3cSAndreas Färber 2607fe55c3cSAndreas Färber return g_test_run(); 2617fe55c3cSAndreas Färber } 262