1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2010-2014 Intel Corporation
11 #include <cmdline_rdline.h>
12 #include <cmdline_parse.h>
13 #include <cmdline_parse_string.h>
14 #include <cmdline_parse_num.h>
15 #include <cmdline_socket.h>
18 #include <rte_lcore.h>
19 #include <rte_ethdev.h>
21 #include <rte_power.h>
23 #include "vm_power_cli_guest.h"
26 #define CHANNEL_PATH "/dev/virtio-ports/virtio.serial.port.poweragent"
29 #define RTE_LOGTYPE_GUEST_CLI RTE_LOGTYPE_USER1
31 struct cmd_quit_result {
32 cmdline_fixed_string_t quit;
36 struct rte_ether_addr addr;
40 static struct rte_power_channel_packet policy;
42 struct rte_power_channel_packet *
49 set_policy_mac(int port, int idx)
51 struct rte_power_channel_packet *policy;
55 /* Use port MAC address as the vfid */
56 ret = rte_eth_macaddr_get(port, &pfid.addr);
58 printf("Failed to get device (port %u) MAC address: %s\n",
59 port, rte_strerror(-ret));
63 printf("Port %u MAC: %02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":"
64 "%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 "\n",
66 pfid.addr.addr_bytes[0], pfid.addr.addr_bytes[1],
67 pfid.addr.addr_bytes[2], pfid.addr.addr_bytes[3],
68 pfid.addr.addr_bytes[4], pfid.addr.addr_bytes[5]);
69 policy = get_policy();
70 policy->vfid[idx] = pfid.pfid;
75 set_policy_defaults(struct rte_power_channel_packet *pkt)
79 ret = set_policy_mac(0, 0);
81 pkt->nb_mac_to_monitor = 0;
83 pkt->nb_mac_to_monitor = 1;
85 pkt->t_boost_status.tbEnabled = false;
87 pkt->vcpu_to_control[0] = 0;
88 pkt->vcpu_to_control[1] = 1;
90 /* Dummy Population. */
91 pkt->traffic_policy.min_packet_thresh = 96000;
92 pkt->traffic_policy.avg_max_packet_thresh = 1800000;
93 pkt->traffic_policy.max_max_packet_thresh = 2000000;
95 pkt->timer_policy.busy_hours[0] = 3;
96 pkt->timer_policy.busy_hours[1] = 4;
97 pkt->timer_policy.busy_hours[2] = 5;
98 pkt->timer_policy.quiet_hours[0] = 11;
99 pkt->timer_policy.quiet_hours[1] = 12;
100 pkt->timer_policy.quiet_hours[2] = 13;
102 pkt->timer_policy.hours_to_use_traffic_profile[0] = 8;
103 pkt->timer_policy.hours_to_use_traffic_profile[1] = 10;
105 pkt->core_type = RTE_POWER_CORE_TYPE_VIRTUAL;
106 pkt->workload = RTE_POWER_WL_LOW;
107 pkt->policy_to_use = RTE_POWER_POLICY_TIME;
108 pkt->command = RTE_POWER_PKT_POLICY;
109 strlcpy(pkt->vm_name, "ubuntu2", sizeof(pkt->vm_name));
114 static void cmd_quit_parsed(__rte_unused void *parsed_result,
115 __rte_unused struct cmdline *cl,
116 __rte_unused void *data)
120 RTE_LCORE_FOREACH(lcore_id) {
121 rte_power_exit(lcore_id);
126 cmdline_parse_token_string_t cmd_quit_quit =
127 TOKEN_STRING_INITIALIZER(struct cmd_quit_result, quit, "quit");
129 cmdline_parse_inst_t cmd_quit = {
130 .f = cmd_quit_parsed, /* function to call */
131 .data = NULL, /* 2nd arg of func */
132 .help_str = "close the application",
133 .tokens = { /* token list, NULL terminated */
134 (void *)&cmd_quit_quit,
139 /* *** VM operations *** */
141 struct cmd_freq_list_result {
142 cmdline_fixed_string_t query_freq;
143 cmdline_fixed_string_t cpu_num;
147 query_data(struct rte_power_channel_packet *pkt, unsigned int lcore_id)
150 ret = rte_power_guest_channel_send_msg(pkt, lcore_id);
152 RTE_LOG(ERR, GUEST_CLI, "Error sending message.\n");
159 receive_freq_list(struct rte_power_channel_packet_freq_list *pkt_freq_list,
160 unsigned int lcore_id)
164 ret = rte_power_guest_channel_receive_msg(pkt_freq_list,
165 sizeof(*pkt_freq_list),
168 RTE_LOG(ERR, GUEST_CLI, "Error receiving message.\n");
171 if (pkt_freq_list->command != RTE_POWER_FREQ_LIST) {
172 RTE_LOG(ERR, GUEST_CLI, "Unexpected message received.\n");
179 cmd_query_freq_list_parsed(void *parsed_result,
180 __rte_unused struct cmdline *cl,
181 __rte_unused void *data)
183 struct cmd_freq_list_result *res = parsed_result;
184 unsigned int lcore_id;
185 struct rte_power_channel_packet_freq_list pkt_freq_list;
186 struct rte_power_channel_packet pkt;
187 bool query_list = false;
191 memset(&pkt, 0, sizeof(pkt));
192 memset(&pkt_freq_list, 0, sizeof(pkt_freq_list));
194 if (!strcmp(res->cpu_num, "all")) {
196 /* Get first enabled lcore. */
197 lcore_id = rte_get_next_lcore(-1,
200 if (lcore_id == RTE_MAX_LCORE) {
201 cmdline_printf(cl, "Enabled core not found.\n");
205 pkt.command = RTE_POWER_QUERY_FREQ_LIST;
206 strlcpy(pkt.vm_name, policy.vm_name, sizeof(pkt.vm_name));
210 lcore_id = (unsigned int)strtol(res->cpu_num, &ep, 10);
211 if (errno != 0 || lcore_id >= RTE_POWER_MAX_VCPU_PER_VM ||
212 ep == res->cpu_num) {
213 cmdline_printf(cl, "Invalid parameter provided.\n");
216 pkt.command = RTE_POWER_QUERY_FREQ;
217 strlcpy(pkt.vm_name, policy.vm_name, sizeof(pkt.vm_name));
218 pkt.resource_id = lcore_id;
221 ret = query_data(&pkt, lcore_id);
223 cmdline_printf(cl, "Error during sending frequency list query.\n");
227 ret = receive_freq_list(&pkt_freq_list, lcore_id);
229 cmdline_printf(cl, "Error during frequency list reception.\n");
234 for (i = 0; i < pkt_freq_list.num_vcpu; ++i)
235 cmdline_printf(cl, "Frequency of [%d] vcore is %d.\n",
237 pkt_freq_list.freq_list[i]);
239 cmdline_printf(cl, "Frequency of [%d] vcore is %d.\n",
241 pkt_freq_list.freq_list[lcore_id]);
245 cmdline_parse_token_string_t cmd_query_freq_token =
246 TOKEN_STRING_INITIALIZER(struct cmd_freq_list_result, query_freq, "query_cpu_freq");
247 cmdline_parse_token_string_t cmd_query_freq_cpu_num_token =
248 TOKEN_STRING_INITIALIZER(struct cmd_freq_list_result, cpu_num, NULL);
250 cmdline_parse_inst_t cmd_query_freq_list = {
251 .f = cmd_query_freq_list_parsed, /* function to call */
252 .data = NULL, /* 2nd arg of func */
253 .help_str = "query_cpu_freq <core_num>|all, request"
254 " information regarding virtual core frequencies."
255 " The keyword 'all' will query list of all vcores for the VM",
256 .tokens = { /* token list, NULL terminated */
257 (void *)&cmd_query_freq_token,
258 (void *)&cmd_query_freq_cpu_num_token,
263 struct cmd_query_caps_result {
264 cmdline_fixed_string_t query_caps;
265 cmdline_fixed_string_t cpu_num;
269 receive_capabilities(struct rte_power_channel_packet_caps_list *pkt_caps_list,
270 unsigned int lcore_id)
274 ret = rte_power_guest_channel_receive_msg(pkt_caps_list,
275 sizeof(*pkt_caps_list),
278 RTE_LOG(ERR, GUEST_CLI, "Error receiving message.\n");
281 if (pkt_caps_list->command != RTE_POWER_CAPS_LIST) {
282 RTE_LOG(ERR, GUEST_CLI, "Unexpected message received.\n");
289 cmd_query_caps_list_parsed(void *parsed_result,
290 __rte_unused struct cmdline *cl,
291 __rte_unused void *data)
293 struct cmd_query_caps_result *res = parsed_result;
294 unsigned int lcore_id;
295 struct rte_power_channel_packet_caps_list pkt_caps_list;
296 struct rte_power_channel_packet pkt;
297 bool query_list = false;
301 memset(&pkt, 0, sizeof(pkt));
302 memset(&pkt_caps_list, 0, sizeof(pkt_caps_list));
304 if (!strcmp(res->cpu_num, "all")) {
306 /* Get first enabled lcore. */
307 lcore_id = rte_get_next_lcore(-1,
310 if (lcore_id == RTE_MAX_LCORE) {
311 cmdline_printf(cl, "Enabled core not found.\n");
315 pkt.command = RTE_POWER_QUERY_CAPS_LIST;
316 strlcpy(pkt.vm_name, policy.vm_name, sizeof(pkt.vm_name));
320 lcore_id = (unsigned int)strtol(res->cpu_num, &ep, 10);
321 if (errno != 0 || lcore_id >= RTE_POWER_MAX_VCPU_PER_VM ||
322 ep == res->cpu_num) {
323 cmdline_printf(cl, "Invalid parameter provided.\n");
326 pkt.command = RTE_POWER_QUERY_CAPS;
327 strlcpy(pkt.vm_name, policy.vm_name, sizeof(pkt.vm_name));
328 pkt.resource_id = lcore_id;
331 ret = query_data(&pkt, lcore_id);
333 cmdline_printf(cl, "Error during sending capabilities query.\n");
337 ret = receive_capabilities(&pkt_caps_list, lcore_id);
339 cmdline_printf(cl, "Error during capabilities reception.\n");
344 for (i = 0; i < pkt_caps_list.num_vcpu; ++i)
345 cmdline_printf(cl, "Capabilities of [%d] vcore are:"
346 " turbo possibility: %" PRId64 ", "
347 "is priority core: %" PRId64 ".\n",
349 pkt_caps_list.turbo[i],
350 pkt_caps_list.priority[i]);
352 cmdline_printf(cl, "Capabilities of [%d] vcore are:"
353 " turbo possibility: %" PRId64 ", "
354 "is priority core: %" PRId64 ".\n",
356 pkt_caps_list.turbo[lcore_id],
357 pkt_caps_list.priority[lcore_id]);
361 cmdline_parse_token_string_t cmd_query_caps_token =
362 TOKEN_STRING_INITIALIZER(struct cmd_query_caps_result, query_caps, "query_cpu_caps");
363 cmdline_parse_token_string_t cmd_query_caps_cpu_num_token =
364 TOKEN_STRING_INITIALIZER(struct cmd_query_caps_result, cpu_num, NULL);
366 cmdline_parse_inst_t cmd_query_caps_list = {
367 .f = cmd_query_caps_list_parsed, /* function to call */
368 .data = NULL, /* 2nd arg of func */
369 .help_str = "query_cpu_caps <core_num>|all, request"
370 " information regarding virtual core capabilities."
371 " The keyword 'all' will query list of all vcores for the VM",
372 .tokens = { /* token list, NULL terminated */
373 (void *)&cmd_query_caps_token,
374 (void *)&cmd_query_caps_cpu_num_token,
380 check_response_cmd(unsigned int lcore_id, int *result)
382 struct rte_power_channel_packet pkt;
385 ret = rte_power_guest_channel_receive_msg(&pkt, sizeof pkt, lcore_id);
389 switch (pkt.command) {
390 case(RTE_POWER_CMD_ACK):
393 case(RTE_POWER_CMD_NACK):
397 RTE_LOG(ERR, GUEST_CLI,
398 "Received invalid response from host, expecting ACK/NACK.\n");
405 struct cmd_set_cpu_freq_result {
406 cmdline_fixed_string_t set_cpu_freq;
408 cmdline_fixed_string_t cmd;
412 cmd_set_cpu_freq_parsed(void *parsed_result, struct cmdline *cl,
413 __rte_unused void *data)
416 struct cmd_set_cpu_freq_result *res = parsed_result;
418 if (!strcmp(res->cmd, "up"))
419 ret = rte_power_freq_up(res->lcore_id);
420 else if (!strcmp(res->cmd, "down"))
421 ret = rte_power_freq_down(res->lcore_id);
422 else if (!strcmp(res->cmd, "min"))
423 ret = rte_power_freq_min(res->lcore_id);
424 else if (!strcmp(res->cmd, "max"))
425 ret = rte_power_freq_max(res->lcore_id);
426 else if (!strcmp(res->cmd, "enable_turbo"))
427 ret = rte_power_freq_enable_turbo(res->lcore_id);
428 else if (!strcmp(res->cmd, "disable_turbo"))
429 ret = rte_power_freq_disable_turbo(res->lcore_id);
432 cmdline_printf(cl, "Error sending message: %s\n", strerror(ret));
436 ret = check_response_cmd(res->lcore_id, &result);
438 RTE_LOG(ERR, GUEST_CLI, "No confirmation for sent message received\n");
440 cmdline_printf(cl, "%s received for message sent to host.\n",
441 result == 1 ? "ACK" : "NACK");
445 cmdline_parse_token_string_t cmd_set_cpu_freq =
446 TOKEN_STRING_INITIALIZER(struct cmd_set_cpu_freq_result,
447 set_cpu_freq, "set_cpu_freq");
448 cmdline_parse_token_num_t cmd_set_cpu_freq_core_num =
449 TOKEN_NUM_INITIALIZER(struct cmd_set_cpu_freq_result,
450 lcore_id, RTE_UINT8);
451 cmdline_parse_token_string_t cmd_set_cpu_freq_cmd_cmd =
452 TOKEN_STRING_INITIALIZER(struct cmd_set_cpu_freq_result,
453 cmd, "up#down#min#max#enable_turbo#disable_turbo");
455 cmdline_parse_inst_t cmd_set_cpu_freq_set = {
456 .f = cmd_set_cpu_freq_parsed,
458 .help_str = "set_cpu_freq <core_num> "
459 "<up|down|min|max|enable_turbo|disable_turbo>, "
460 "adjust the frequency for the specified core.",
462 (void *)&cmd_set_cpu_freq,
463 (void *)&cmd_set_cpu_freq_core_num,
464 (void *)&cmd_set_cpu_freq_cmd_cmd,
469 struct cmd_send_policy_result {
470 cmdline_fixed_string_t send_policy;
471 cmdline_fixed_string_t cmd;
475 send_policy(struct rte_power_channel_packet *pkt, struct cmdline *cl)
479 ret = rte_power_guest_channel_send_msg(pkt, 1);
481 RTE_LOG(ERR, GUEST_CLI, "Error sending message: %s\n",
482 ret > 0 ? strerror(ret) : "channel not connected");
487 ret = check_response_cmd(1, &result);
489 RTE_LOG(ERR, GUEST_CLI, "No confirmation for sent policy received\n");
491 cmdline_printf(cl, "%s for sent policy received.\n",
492 result == 1 ? "ACK" : "NACK");
498 cmd_send_policy_parsed(void *parsed_result, struct cmdline *cl,
499 __rte_unused void *data)
502 struct cmd_send_policy_result *res = parsed_result;
504 if (!strcmp(res->cmd, "now")) {
505 printf("Sending Policy down now!\n");
506 ret = send_policy(&policy, cl);
509 cmdline_printf(cl, "Error sending message: %s\n",
513 cmdline_parse_token_string_t cmd_send_policy =
514 TOKEN_STRING_INITIALIZER(struct cmd_send_policy_result,
515 send_policy, "send_policy");
516 cmdline_parse_token_string_t cmd_send_policy_cmd_cmd =
517 TOKEN_STRING_INITIALIZER(struct cmd_send_policy_result,
520 cmdline_parse_inst_t cmd_send_policy_set = {
521 .f = cmd_send_policy_parsed,
523 .help_str = "send_policy now",
525 (void *)&cmd_send_policy,
526 (void *)&cmd_send_policy_cmd_cmd,
531 cmdline_parse_ctx_t main_ctx[] = {
532 (cmdline_parse_inst_t *)&cmd_quit,
533 (cmdline_parse_inst_t *)&cmd_send_policy_set,
534 (cmdline_parse_inst_t *)&cmd_set_cpu_freq_set,
535 (cmdline_parse_inst_t *)&cmd_query_freq_list,
536 (cmdline_parse_inst_t *)&cmd_query_caps_list,
541 run_cli(__rte_unused void *arg)
545 cl = cmdline_stdin_new(main_ctx, "vmpower(guest)> ");
549 cmdline_interact(cl);
550 cmdline_stdin_exit(cl);