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" 137fe55c3cSAndreas Färber #include "libqtest.h" 14*452fcdbcSMarkus Armbruster #include "qapi/qmp/qdict.h" 157fe55c3cSAndreas Färber 16152e0393SThomas Huth struct PlugTestData { 1734e46f60SMarc-André Lureau char *machine; 187fe55c3cSAndreas Färber const char *cpu_model; 1980b8c0beSThomas Huth char *device_model; 207fe55c3cSAndreas Färber unsigned sockets; 217fe55c3cSAndreas Färber unsigned cores; 227fe55c3cSAndreas Färber unsigned threads; 237fe55c3cSAndreas Färber unsigned maxcpus; 247fe55c3cSAndreas Färber }; 25152e0393SThomas Huth typedef struct PlugTestData PlugTestData; 267fe55c3cSAndreas Färber 27152e0393SThomas Huth static void test_plug_with_cpu_add(gconstpointer data) 287fe55c3cSAndreas Färber { 29152e0393SThomas Huth const PlugTestData *s = data; 307fe55c3cSAndreas Färber char *args; 317fe55c3cSAndreas Färber QDict *response; 327fe55c3cSAndreas Färber unsigned int i; 337fe55c3cSAndreas Färber 347fe55c3cSAndreas Färber args = g_strdup_printf("-machine %s -cpu %s " 357fe55c3cSAndreas Färber "-smp sockets=%u,cores=%u,threads=%u,maxcpus=%u", 367fe55c3cSAndreas Färber s->machine, s->cpu_model, 377fe55c3cSAndreas Färber s->sockets, s->cores, s->threads, s->maxcpus); 387fe55c3cSAndreas Färber qtest_start(args); 397fe55c3cSAndreas Färber 407fe55c3cSAndreas Färber for (i = s->sockets * s->cores * s->threads; i < s->maxcpus; i++) { 417fe55c3cSAndreas Färber response = qmp("{ 'execute': 'cpu-add'," 427fe55c3cSAndreas Färber " 'arguments': { 'id': %d } }", i); 437fe55c3cSAndreas Färber g_assert(response); 447fe55c3cSAndreas Färber g_assert(!qdict_haskey(response, "error")); 457fe55c3cSAndreas Färber QDECREF(response); 467fe55c3cSAndreas Färber } 477fe55c3cSAndreas Färber 487fe55c3cSAndreas Färber qtest_end(); 497fe55c3cSAndreas Färber g_free(args); 507fe55c3cSAndreas Färber } 517fe55c3cSAndreas Färber 52152e0393SThomas Huth static void test_plug_without_cpu_add(gconstpointer data) 537fe55c3cSAndreas Färber { 54152e0393SThomas Huth const PlugTestData *s = data; 557fe55c3cSAndreas Färber char *args; 567fe55c3cSAndreas Färber QDict *response; 577fe55c3cSAndreas Färber 587fe55c3cSAndreas Färber args = g_strdup_printf("-machine %s -cpu %s " 597fe55c3cSAndreas Färber "-smp sockets=%u,cores=%u,threads=%u,maxcpus=%u", 607fe55c3cSAndreas Färber s->machine, s->cpu_model, 617fe55c3cSAndreas Färber s->sockets, s->cores, s->threads, s->maxcpus); 627fe55c3cSAndreas Färber qtest_start(args); 637fe55c3cSAndreas Färber 647fe55c3cSAndreas Färber response = qmp("{ 'execute': 'cpu-add'," 657fe55c3cSAndreas Färber " 'arguments': { 'id': %d } }", 667fe55c3cSAndreas Färber s->sockets * s->cores * s->threads); 677fe55c3cSAndreas Färber g_assert(response); 687fe55c3cSAndreas Färber g_assert(qdict_haskey(response, "error")); 697fe55c3cSAndreas Färber QDECREF(response); 707fe55c3cSAndreas Färber 717fe55c3cSAndreas Färber qtest_end(); 727fe55c3cSAndreas Färber g_free(args); 737fe55c3cSAndreas Färber } 747fe55c3cSAndreas Färber 7580b8c0beSThomas Huth static void test_plug_with_device_add_x86(gconstpointer data) 7680b8c0beSThomas Huth { 7780b8c0beSThomas Huth const PlugTestData *td = data; 7880b8c0beSThomas Huth char *args; 7980b8c0beSThomas Huth unsigned int s, c, t; 8080b8c0beSThomas Huth 8180b8c0beSThomas Huth args = g_strdup_printf("-machine %s -cpu %s " 8280b8c0beSThomas Huth "-smp sockets=%u,cores=%u,threads=%u,maxcpus=%u", 8380b8c0beSThomas Huth td->machine, td->cpu_model, 8480b8c0beSThomas Huth td->sockets, td->cores, td->threads, td->maxcpus); 8580b8c0beSThomas Huth qtest_start(args); 8680b8c0beSThomas Huth 8780b8c0beSThomas Huth for (s = td->sockets; s < td->maxcpus / td->cores / td->threads; s++) { 8880b8c0beSThomas Huth for (c = 0; c < td->cores; c++) { 8980b8c0beSThomas Huth for (t = 0; t < td->threads; t++) { 9080b8c0beSThomas Huth char *id = g_strdup_printf("id-%i-%i-%i", s, c, t); 9180b8c0beSThomas Huth qtest_qmp_device_add(td->device_model, id, "'socket-id':'%i', " 9280b8c0beSThomas Huth "'core-id':'%i', 'thread-id':'%i'", 9380b8c0beSThomas Huth s, c, t); 9480b8c0beSThomas Huth g_free(id); 9580b8c0beSThomas Huth } 9680b8c0beSThomas Huth } 9780b8c0beSThomas Huth } 9880b8c0beSThomas Huth 9980b8c0beSThomas Huth qtest_end(); 10080b8c0beSThomas Huth g_free(args); 10180b8c0beSThomas Huth } 10280b8c0beSThomas Huth 10373a7d31eSThomas Huth static void test_plug_with_device_add_coreid(gconstpointer data) 10473a7d31eSThomas Huth { 10573a7d31eSThomas Huth const PlugTestData *td = data; 10673a7d31eSThomas Huth char *args; 10773a7d31eSThomas Huth unsigned int c; 10873a7d31eSThomas Huth 10973a7d31eSThomas Huth args = g_strdup_printf("-machine %s -cpu %s " 11073a7d31eSThomas Huth "-smp 1,sockets=%u,cores=%u,threads=%u,maxcpus=%u", 11173a7d31eSThomas Huth td->machine, td->cpu_model, 11273a7d31eSThomas Huth td->sockets, td->cores, td->threads, td->maxcpus); 11373a7d31eSThomas Huth qtest_start(args); 11473a7d31eSThomas Huth 11573a7d31eSThomas Huth for (c = td->cores; c < td->maxcpus / td->sockets / td->threads; c++) { 11673a7d31eSThomas Huth char *id = g_strdup_printf("id-%i", c); 11773a7d31eSThomas Huth qtest_qmp_device_add(td->device_model, id, "'core-id':'%i'", c); 11873a7d31eSThomas Huth g_free(id); 11973a7d31eSThomas Huth } 12073a7d31eSThomas Huth 12173a7d31eSThomas Huth qtest_end(); 12273a7d31eSThomas Huth g_free(args); 12373a7d31eSThomas Huth } 12473a7d31eSThomas Huth 12534e46f60SMarc-André Lureau static void test_data_free(gpointer data) 12634e46f60SMarc-André Lureau { 127152e0393SThomas Huth PlugTestData *pc = data; 12834e46f60SMarc-André Lureau 12934e46f60SMarc-André Lureau g_free(pc->machine); 13080b8c0beSThomas Huth g_free(pc->device_model); 13134e46f60SMarc-André Lureau g_free(pc); 13234e46f60SMarc-André Lureau } 13334e46f60SMarc-André Lureau 13402ef6e87SThomas Huth static void add_pc_test_case(const char *mname) 1357fe55c3cSAndreas Färber { 13634e46f60SMarc-André Lureau char *path; 137152e0393SThomas Huth PlugTestData *data; 1387fe55c3cSAndreas Färber 1397fe55c3cSAndreas Färber if (!g_str_has_prefix(mname, "pc-")) { 14002ef6e87SThomas Huth return; 1417fe55c3cSAndreas Färber } 142152e0393SThomas Huth data = g_new(PlugTestData, 1); 14334e46f60SMarc-André Lureau data->machine = g_strdup(mname); 1447fe55c3cSAndreas Färber data->cpu_model = "Haswell"; /* 1.3+ theoretically */ 14580b8c0beSThomas Huth data->device_model = g_strdup_printf("%s-%s-cpu", data->cpu_model, 14680b8c0beSThomas Huth qtest_get_arch()); 1477fe55c3cSAndreas Färber data->sockets = 1; 1487fe55c3cSAndreas Färber data->cores = 3; 1497fe55c3cSAndreas Färber data->threads = 2; 1507fe55c3cSAndreas Färber data->maxcpus = data->sockets * data->cores * data->threads * 2; 1517fe55c3cSAndreas Färber if (g_str_has_suffix(mname, "-1.4") || 1527fe55c3cSAndreas Färber (strcmp(mname, "pc-1.3") == 0) || 1537fe55c3cSAndreas Färber (strcmp(mname, "pc-1.2") == 0) || 1547fe55c3cSAndreas Färber (strcmp(mname, "pc-1.1") == 0) || 1557fe55c3cSAndreas Färber (strcmp(mname, "pc-1.0") == 0) || 1567fe55c3cSAndreas Färber (strcmp(mname, "pc-0.15") == 0) || 1577fe55c3cSAndreas Färber (strcmp(mname, "pc-0.14") == 0) || 1587fe55c3cSAndreas Färber (strcmp(mname, "pc-0.13") == 0) || 1597fe55c3cSAndreas Färber (strcmp(mname, "pc-0.12") == 0) || 1607fe55c3cSAndreas Färber (strcmp(mname, "pc-0.11") == 0) || 1617fe55c3cSAndreas Färber (strcmp(mname, "pc-0.10") == 0)) { 16280b8c0beSThomas Huth path = g_strdup_printf("cpu-plug/%s/init/%ux%ux%u&maxcpus=%u", 16353f77e45SAndreas Färber mname, data->sockets, data->cores, 1647fe55c3cSAndreas Färber data->threads, data->maxcpus); 165152e0393SThomas Huth qtest_add_data_func_full(path, data, test_plug_without_cpu_add, 16634e46f60SMarc-André Lureau test_data_free); 16734e46f60SMarc-André Lureau g_free(path); 1687fe55c3cSAndreas Färber } else { 16980b8c0beSThomas Huth PlugTestData *data2 = g_memdup(data, sizeof(PlugTestData)); 17080b8c0beSThomas Huth 17180b8c0beSThomas Huth data2->machine = g_strdup(data->machine); 17280b8c0beSThomas Huth data2->device_model = g_strdup(data->device_model); 17380b8c0beSThomas Huth 17480b8c0beSThomas Huth path = g_strdup_printf("cpu-plug/%s/cpu-add/%ux%ux%u&maxcpus=%u", 17553f77e45SAndreas Färber mname, data->sockets, data->cores, 1767fe55c3cSAndreas Färber data->threads, data->maxcpus); 177152e0393SThomas Huth qtest_add_data_func_full(path, data, test_plug_with_cpu_add, 17834e46f60SMarc-André Lureau test_data_free); 17934e46f60SMarc-André Lureau g_free(path); 18080b8c0beSThomas Huth path = g_strdup_printf("cpu-plug/%s/device-add/%ux%ux%u&maxcpus=%u", 18180b8c0beSThomas Huth mname, data2->sockets, data2->cores, 18280b8c0beSThomas Huth data2->threads, data2->maxcpus); 18380b8c0beSThomas Huth qtest_add_data_func_full(path, data2, test_plug_with_device_add_x86, 18480b8c0beSThomas Huth test_data_free); 18580b8c0beSThomas Huth g_free(path); 1867fe55c3cSAndreas Färber } 1877fe55c3cSAndreas Färber } 1887fe55c3cSAndreas Färber 18973a7d31eSThomas Huth static void add_pseries_test_case(const char *mname) 19073a7d31eSThomas Huth { 19173a7d31eSThomas Huth char *path; 19273a7d31eSThomas Huth PlugTestData *data; 19373a7d31eSThomas Huth 19473a7d31eSThomas Huth if (!g_str_has_prefix(mname, "pseries-") || 19573a7d31eSThomas Huth (g_str_has_prefix(mname, "pseries-2.") && atoi(&mname[10]) < 7)) { 19673a7d31eSThomas Huth return; 19773a7d31eSThomas Huth } 19873a7d31eSThomas Huth data = g_new(PlugTestData, 1); 19973a7d31eSThomas Huth data->machine = g_strdup(mname); 20073a7d31eSThomas Huth data->cpu_model = "power8_v2.0"; 20173a7d31eSThomas Huth data->device_model = g_strdup("power8_v2.0-spapr-cpu-core"); 20273a7d31eSThomas Huth data->sockets = 2; 20373a7d31eSThomas Huth data->cores = 3; 20473a7d31eSThomas Huth data->threads = 1; 20573a7d31eSThomas Huth data->maxcpus = data->sockets * data->cores * data->threads * 2; 20673a7d31eSThomas Huth 20773a7d31eSThomas Huth path = g_strdup_printf("cpu-plug/%s/device-add/%ux%ux%u&maxcpus=%u", 20873a7d31eSThomas Huth mname, data->sockets, data->cores, 20973a7d31eSThomas Huth data->threads, data->maxcpus); 21073a7d31eSThomas Huth qtest_add_data_func_full(path, data, test_plug_with_device_add_coreid, 21173a7d31eSThomas Huth test_data_free); 21273a7d31eSThomas Huth g_free(path); 21373a7d31eSThomas Huth } 21473a7d31eSThomas Huth 2157d8b00faSThomas Huth static void add_s390x_test_case(const char *mname) 2167d8b00faSThomas Huth { 2177d8b00faSThomas Huth char *path; 2187d8b00faSThomas Huth PlugTestData *data, *data2; 2197d8b00faSThomas Huth 2207d8b00faSThomas Huth if (!g_str_has_prefix(mname, "s390-ccw-virtio-")) { 2217d8b00faSThomas Huth return; 2227d8b00faSThomas Huth } 2237d8b00faSThomas Huth 2247d8b00faSThomas Huth data = g_new(PlugTestData, 1); 2257d8b00faSThomas Huth data->machine = g_strdup(mname); 2267d8b00faSThomas Huth data->cpu_model = "qemu"; 2277d8b00faSThomas Huth data->device_model = g_strdup("qemu-s390x-cpu"); 2287d8b00faSThomas Huth data->sockets = 1; 2297d8b00faSThomas Huth data->cores = 3; 2307d8b00faSThomas Huth data->threads = 1; 2317d8b00faSThomas Huth data->maxcpus = data->sockets * data->cores * data->threads * 2; 2327d8b00faSThomas Huth 2337d8b00faSThomas Huth data2 = g_memdup(data, sizeof(PlugTestData)); 2347d8b00faSThomas Huth data2->machine = g_strdup(data->machine); 2357d8b00faSThomas Huth data2->device_model = g_strdup(data->device_model); 2367d8b00faSThomas Huth 2377d8b00faSThomas Huth path = g_strdup_printf("cpu-plug/%s/cpu-add/%ux%ux%u&maxcpus=%u", 2387d8b00faSThomas Huth mname, data->sockets, data->cores, 2397d8b00faSThomas Huth data->threads, data->maxcpus); 2407d8b00faSThomas Huth qtest_add_data_func_full(path, data, test_plug_with_cpu_add, 2417d8b00faSThomas Huth test_data_free); 2427d8b00faSThomas Huth g_free(path); 2437d8b00faSThomas Huth 2447d8b00faSThomas Huth path = g_strdup_printf("cpu-plug/%s/device-add/%ux%ux%u&maxcpus=%u", 2457d8b00faSThomas Huth mname, data2->sockets, data2->cores, 2467d8b00faSThomas Huth data2->threads, data2->maxcpus); 2477d8b00faSThomas Huth qtest_add_data_func_full(path, data2, test_plug_with_device_add_coreid, 2487d8b00faSThomas Huth test_data_free); 2497d8b00faSThomas Huth g_free(path); 2507d8b00faSThomas Huth } 2517d8b00faSThomas Huth 2527fe55c3cSAndreas Färber int main(int argc, char **argv) 2537fe55c3cSAndreas Färber { 2547fe55c3cSAndreas Färber const char *arch = qtest_get_arch(); 2557fe55c3cSAndreas Färber 2567fe55c3cSAndreas Färber g_test_init(&argc, &argv, NULL); 2577fe55c3cSAndreas Färber 2587fe55c3cSAndreas Färber if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { 25902ef6e87SThomas Huth qtest_cb_for_every_machine(add_pc_test_case); 26073a7d31eSThomas Huth } else if (g_str_equal(arch, "ppc64")) { 26173a7d31eSThomas Huth qtest_cb_for_every_machine(add_pseries_test_case); 2627d8b00faSThomas Huth } else if (g_str_equal(arch, "s390x")) { 2637d8b00faSThomas Huth qtest_cb_for_every_machine(add_s390x_test_case); 2647fe55c3cSAndreas Färber } 2657fe55c3cSAndreas Färber 2667fe55c3cSAndreas Färber return g_test_run(); 2677fe55c3cSAndreas Färber } 268