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" 15*021a007eSIgor 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 76*021a007eSIgor 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; 81*021a007eSIgor Mammedov QDict *resp; 82*021a007eSIgor Mammedov QList *cpus; 83*021a007eSIgor Mammedov QObject *e; 84*021a007eSIgor 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 92*021a007eSIgor Mammedov resp = qtest_qmp(qts, "{ 'execute': 'query-hotpluggable-cpus'}"); 93*021a007eSIgor Mammedov g_assert(qdict_haskey(resp, "return")); 94*021a007eSIgor Mammedov cpus = qdict_get_qlist(resp, "return"); 95*021a007eSIgor Mammedov g_assert(cpus); 96*021a007eSIgor Mammedov 97*021a007eSIgor Mammedov while ((e = qlist_pop(cpus))) { 98*021a007eSIgor Mammedov const QDict *cpu, *props; 99*021a007eSIgor Mammedov 100*021a007eSIgor Mammedov cpu = qobject_to(QDict, e); 101*021a007eSIgor Mammedov if (qdict_haskey(cpu, "qom-path")) { 102*021a007eSIgor Mammedov continue; 10380b8c0beSThomas Huth } 10480b8c0beSThomas Huth 105*021a007eSIgor Mammedov g_assert(qdict_haskey(cpu, "props")); 106*021a007eSIgor Mammedov props = qdict_get_qdict(cpu, "props"); 107*021a007eSIgor Mammedov 108*021a007eSIgor Mammedov qtest_qmp_device_add_qdict(qts, td->device_model, props); 109*021a007eSIgor Mammedov hotplugged++; 11080b8c0beSThomas Huth } 11180b8c0beSThomas Huth 112*021a007eSIgor Mammedov /* make sure that there were hotplugged CPUs */ 113*021a007eSIgor Mammedov g_assert(hotplugged); 114*021a007eSIgor Mammedov qobject_unref(resp); 115e5758de4SThomas Huth qtest_quit(qts); 11673a7d31eSThomas Huth g_free(args); 11773a7d31eSThomas Huth } 11873a7d31eSThomas Huth 11934e46f60SMarc-André Lureau static void test_data_free(gpointer data) 12034e46f60SMarc-André Lureau { 121152e0393SThomas Huth PlugTestData *pc = data; 12234e46f60SMarc-André Lureau 12334e46f60SMarc-André Lureau g_free(pc->machine); 12480b8c0beSThomas Huth g_free(pc->device_model); 12534e46f60SMarc-André Lureau g_free(pc); 12634e46f60SMarc-André Lureau } 12734e46f60SMarc-André Lureau 12802ef6e87SThomas Huth static void add_pc_test_case(const char *mname) 1297fe55c3cSAndreas Färber { 13034e46f60SMarc-André Lureau char *path; 131152e0393SThomas Huth PlugTestData *data; 1327fe55c3cSAndreas Färber 1337fe55c3cSAndreas Färber if (!g_str_has_prefix(mname, "pc-")) { 13402ef6e87SThomas Huth return; 1357fe55c3cSAndreas Färber } 136152e0393SThomas Huth data = g_new(PlugTestData, 1); 13734e46f60SMarc-André Lureau data->machine = g_strdup(mname); 1387fe55c3cSAndreas Färber data->cpu_model = "Haswell"; /* 1.3+ theoretically */ 13980b8c0beSThomas Huth data->device_model = g_strdup_printf("%s-%s-cpu", data->cpu_model, 14080b8c0beSThomas Huth qtest_get_arch()); 1417fe55c3cSAndreas Färber data->sockets = 1; 1427fe55c3cSAndreas Färber data->cores = 3; 1437fe55c3cSAndreas Färber data->threads = 2; 144bc1fb850SIgor Mammedov data->maxcpus = data->sockets * data->cores * data->threads; 1457fe55c3cSAndreas Färber if (g_str_has_suffix(mname, "-1.4") || 1467fe55c3cSAndreas Färber (strcmp(mname, "pc-1.3") == 0) || 1477fe55c3cSAndreas Färber (strcmp(mname, "pc-1.2") == 0) || 1487fe55c3cSAndreas Färber (strcmp(mname, "pc-1.1") == 0) || 1497fe55c3cSAndreas Färber (strcmp(mname, "pc-1.0") == 0) || 1507fe55c3cSAndreas Färber (strcmp(mname, "pc-0.15") == 0) || 1517fe55c3cSAndreas Färber (strcmp(mname, "pc-0.14") == 0) || 1527fe55c3cSAndreas Färber (strcmp(mname, "pc-0.13") == 0) || 153cc425b5dSThomas Huth (strcmp(mname, "pc-0.12") == 0)) { 15480b8c0beSThomas Huth path = g_strdup_printf("cpu-plug/%s/init/%ux%ux%u&maxcpus=%u", 15553f77e45SAndreas Färber mname, data->sockets, data->cores, 1567fe55c3cSAndreas Färber data->threads, data->maxcpus); 157152e0393SThomas Huth qtest_add_data_func_full(path, data, test_plug_without_cpu_add, 15834e46f60SMarc-André Lureau test_data_free); 15934e46f60SMarc-André Lureau g_free(path); 1607fe55c3cSAndreas Färber } else { 16180b8c0beSThomas Huth PlugTestData *data2 = g_memdup(data, sizeof(PlugTestData)); 16280b8c0beSThomas Huth 16380b8c0beSThomas Huth data2->machine = g_strdup(data->machine); 16480b8c0beSThomas Huth data2->device_model = g_strdup(data->device_model); 16580b8c0beSThomas Huth 16680b8c0beSThomas Huth path = g_strdup_printf("cpu-plug/%s/cpu-add/%ux%ux%u&maxcpus=%u", 16753f77e45SAndreas Färber mname, data->sockets, data->cores, 1687fe55c3cSAndreas Färber data->threads, data->maxcpus); 169152e0393SThomas Huth qtest_add_data_func_full(path, data, test_plug_with_cpu_add, 17034e46f60SMarc-André Lureau test_data_free); 17134e46f60SMarc-André Lureau g_free(path); 17280b8c0beSThomas Huth path = g_strdup_printf("cpu-plug/%s/device-add/%ux%ux%u&maxcpus=%u", 17380b8c0beSThomas Huth mname, data2->sockets, data2->cores, 17480b8c0beSThomas Huth data2->threads, data2->maxcpus); 175*021a007eSIgor Mammedov qtest_add_data_func_full(path, data2, test_plug_with_device_add, 17680b8c0beSThomas Huth test_data_free); 17780b8c0beSThomas Huth g_free(path); 1787fe55c3cSAndreas Färber } 1797fe55c3cSAndreas Färber } 1807fe55c3cSAndreas Färber 18173a7d31eSThomas Huth static void add_pseries_test_case(const char *mname) 18273a7d31eSThomas Huth { 18373a7d31eSThomas Huth char *path; 18473a7d31eSThomas Huth PlugTestData *data; 18573a7d31eSThomas Huth 18673a7d31eSThomas Huth if (!g_str_has_prefix(mname, "pseries-") || 18773a7d31eSThomas Huth (g_str_has_prefix(mname, "pseries-2.") && atoi(&mname[10]) < 7)) { 18873a7d31eSThomas Huth return; 18973a7d31eSThomas Huth } 19073a7d31eSThomas Huth data = g_new(PlugTestData, 1); 19173a7d31eSThomas Huth data->machine = g_strdup(mname); 19273a7d31eSThomas Huth data->cpu_model = "power8_v2.0"; 19373a7d31eSThomas Huth data->device_model = g_strdup("power8_v2.0-spapr-cpu-core"); 19473a7d31eSThomas Huth data->sockets = 2; 19573a7d31eSThomas Huth data->cores = 3; 19673a7d31eSThomas Huth data->threads = 1; 197bc1fb850SIgor Mammedov data->maxcpus = data->sockets * data->cores * data->threads; 19873a7d31eSThomas Huth 19973a7d31eSThomas Huth path = g_strdup_printf("cpu-plug/%s/device-add/%ux%ux%u&maxcpus=%u", 20073a7d31eSThomas Huth mname, data->sockets, data->cores, 20173a7d31eSThomas Huth data->threads, data->maxcpus); 202*021a007eSIgor Mammedov qtest_add_data_func_full(path, data, test_plug_with_device_add, 20373a7d31eSThomas Huth test_data_free); 20473a7d31eSThomas Huth g_free(path); 20573a7d31eSThomas Huth } 20673a7d31eSThomas Huth 2077d8b00faSThomas Huth static void add_s390x_test_case(const char *mname) 2087d8b00faSThomas Huth { 2097d8b00faSThomas Huth char *path; 2107d8b00faSThomas Huth PlugTestData *data, *data2; 2117d8b00faSThomas Huth 2127d8b00faSThomas Huth if (!g_str_has_prefix(mname, "s390-ccw-virtio-")) { 2137d8b00faSThomas Huth return; 2147d8b00faSThomas Huth } 2157d8b00faSThomas Huth 2167d8b00faSThomas Huth data = g_new(PlugTestData, 1); 2177d8b00faSThomas Huth data->machine = g_strdup(mname); 2187d8b00faSThomas Huth data->cpu_model = "qemu"; 2197d8b00faSThomas Huth data->device_model = g_strdup("qemu-s390x-cpu"); 2207d8b00faSThomas Huth data->sockets = 1; 2217d8b00faSThomas Huth data->cores = 3; 2227d8b00faSThomas Huth data->threads = 1; 223bc1fb850SIgor Mammedov data->maxcpus = data->sockets * data->cores * data->threads; 2247d8b00faSThomas Huth 2257d8b00faSThomas Huth data2 = g_memdup(data, sizeof(PlugTestData)); 2267d8b00faSThomas Huth data2->machine = g_strdup(data->machine); 2277d8b00faSThomas Huth data2->device_model = g_strdup(data->device_model); 2287d8b00faSThomas Huth 2297d8b00faSThomas Huth path = g_strdup_printf("cpu-plug/%s/cpu-add/%ux%ux%u&maxcpus=%u", 2307d8b00faSThomas Huth mname, data->sockets, data->cores, 2317d8b00faSThomas Huth data->threads, data->maxcpus); 2327d8b00faSThomas Huth qtest_add_data_func_full(path, data, test_plug_with_cpu_add, 2337d8b00faSThomas Huth test_data_free); 2347d8b00faSThomas Huth g_free(path); 2357d8b00faSThomas Huth 2367d8b00faSThomas Huth path = g_strdup_printf("cpu-plug/%s/device-add/%ux%ux%u&maxcpus=%u", 2377d8b00faSThomas Huth mname, data2->sockets, data2->cores, 2387d8b00faSThomas Huth data2->threads, data2->maxcpus); 239*021a007eSIgor Mammedov qtest_add_data_func_full(path, data2, test_plug_with_device_add, 2407d8b00faSThomas Huth test_data_free); 2417d8b00faSThomas Huth g_free(path); 2427d8b00faSThomas Huth } 2437d8b00faSThomas Huth 2447fe55c3cSAndreas Färber int main(int argc, char **argv) 2457fe55c3cSAndreas Färber { 2467fe55c3cSAndreas Färber const char *arch = qtest_get_arch(); 2477fe55c3cSAndreas Färber 2487fe55c3cSAndreas Färber g_test_init(&argc, &argv, NULL); 2497fe55c3cSAndreas Färber 2507fe55c3cSAndreas Färber if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { 2511f4a0d81SThomas Huth qtest_cb_for_every_machine(add_pc_test_case, g_test_quick()); 25273a7d31eSThomas Huth } else if (g_str_equal(arch, "ppc64")) { 2531f4a0d81SThomas Huth qtest_cb_for_every_machine(add_pseries_test_case, g_test_quick()); 2547d8b00faSThomas Huth } else if (g_str_equal(arch, "s390x")) { 2551f4a0d81SThomas Huth qtest_cb_for_every_machine(add_s390x_test_case, g_test_quick()); 2567fe55c3cSAndreas Färber } 2577fe55c3cSAndreas Färber 2587fe55c3cSAndreas Färber return g_test_run(); 2597fe55c3cSAndreas Färber } 260