Path: blob/master/tools/power/x86/intel-speed-select/hfi-events.c
26292 views
// SPDX-License-Identifier: GPL-2.01/*2* Intel Speed Select -- Read HFI events for OOB3* Copyright (c) 2022 Intel Corporation.4*/56/*7* This file incorporates work covered by the following copyright and8* permission notice:910* WPA Supplicant - driver interaction with Linux nl80211/cfg8021111* Copyright (c) 2003-2008, Jouni Malinen <[email protected]>12*13* This program is free software; you can redistribute it and/or modify14* it under the terms of the GNU General Public License version 2 as15* published by the Free Software Foundation.16*17* Alternatively, this software may be distributed under the terms of18* BSD license.19*20* Requires21* libnl-genl-3-dev22*23* For Fedora/CenOS24* dnf install libnl3-devel25* For Ubuntu26* apt install libnl-3-dev libnl-genl-3-dev27*/2829#include <stdio.h>30#include <stdlib.h>31#include <stdarg.h>32#include <string.h>33#include <unistd.h>34#include <fcntl.h>35#include <sys/file.h>36#include <sys/types.h>37#include <sys/stat.h>38#include <errno.h>39#include <getopt.h>40#include <signal.h>41#include <netlink/genl/genl.h>42#include <netlink/genl/family.h>43#include <netlink/genl/ctrl.h>4445#include <linux/thermal.h>46#include "isst.h"4748struct hfi_event_data {49struct nl_sock *nl_handle;50struct nl_cb *nl_cb;51};5253struct hfi_event_data drv;5455static int ack_handler(struct nl_msg *msg, void *arg)56{57int *err = arg;58*err = 0;59return NL_STOP;60}6162static int finish_handler(struct nl_msg *msg, void *arg)63{64int *ret = arg;65*ret = 0;66return NL_SKIP;67}6869static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,70void *arg)71{72int *ret = arg;73*ret = err->error;74return NL_SKIP;75}7677static int seq_check_handler(struct nl_msg *msg, void *arg)78{79return NL_OK;80}8182static int send_and_recv_msgs(struct hfi_event_data *drv,83struct nl_msg *msg,84int (*valid_handler)(struct nl_msg *, void *),85void *valid_data)86{87struct nl_cb *cb;88int err = -ENOMEM;8990cb = nl_cb_clone(drv->nl_cb);91if (!cb)92goto out;9394err = nl_send_auto_complete(drv->nl_handle, msg);95if (err < 0)96goto out;9798err = 1;99100nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);101nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);102nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);103104if (valid_handler)105nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,106valid_handler, valid_data);107108while (err > 0)109nl_recvmsgs(drv->nl_handle, cb);110out:111nl_cb_put(cb);112nlmsg_free(msg);113return err;114}115116struct family_data {117const char *group;118int id;119};120121static int family_handler(struct nl_msg *msg, void *arg)122{123struct family_data *res = arg;124struct nlattr *tb[CTRL_ATTR_MAX + 1];125struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));126struct nlattr *mcgrp;127int i;128129nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0),130genlmsg_attrlen(gnlh, 0), NULL);131if (!tb[CTRL_ATTR_MCAST_GROUPS])132return NL_SKIP;133134nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) {135struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1];136nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mcgrp),137nla_len(mcgrp), NULL);138if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] ||139!tb2[CTRL_ATTR_MCAST_GRP_ID] ||140strncmp(nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]),141res->group,142nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME])) != 0)143continue;144res->id = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]);145break;146}147148return 0;149}150151static int nl_get_multicast_id(struct hfi_event_data *drv,152const char *family, const char *group)153{154struct nl_msg *msg;155int ret = -1;156struct family_data res = { group, -ENOENT };157158msg = nlmsg_alloc();159if (!msg)160return -ENOMEM;161genlmsg_put(msg, 0, 0, genl_ctrl_resolve(drv->nl_handle, "nlctrl"),1620, 0, CTRL_CMD_GETFAMILY, 0);163NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family);164165ret = send_and_recv_msgs(drv, msg, family_handler, &res);166msg = NULL;167if (ret == 0)168ret = res.id;169170nla_put_failure:171nlmsg_free(msg);172return ret;173}174175struct perf_cap {176int cpu;177int perf;178int eff;179};180181static void process_hfi_event(struct perf_cap *perf_cap)182{183struct isst_id id;184185set_isst_id(&id, perf_cap->cpu);186process_level_change(&id);187}188189static int handle_event(struct nl_msg *n, void *arg)190{191struct nlmsghdr *nlh = nlmsg_hdr(n);192struct genlmsghdr *genlhdr = genlmsg_hdr(nlh);193struct nlattr *attrs[THERMAL_GENL_ATTR_MAX + 1];194int ret;195struct perf_cap perf_cap = {0};196197ret = genlmsg_parse(nlh, 0, attrs, THERMAL_GENL_ATTR_MAX, NULL);198199debug_printf("Received event %d parse_rer:%d\n", genlhdr->cmd, ret);200if (genlhdr->cmd == THERMAL_GENL_EVENT_CPU_CAPABILITY_CHANGE) {201struct nlattr *cap;202int j, index = 0;203204debug_printf("THERMAL_GENL_EVENT_CPU_CAPABILITY_CHANGE\n");205nla_for_each_nested(cap, attrs[THERMAL_GENL_ATTR_CPU_CAPABILITY], j) {206switch (index) {207case 0:208perf_cap.cpu = nla_get_u32(cap);209break;210case 1:211perf_cap.perf = nla_get_u32(cap);212break;213case 2:214perf_cap.eff = nla_get_u32(cap);215break;216default:217break;218}219++index;220if (index == 3) {221index = 0;222process_hfi_event(&perf_cap);223}224}225}226227return 0;228}229230static int _hfi_exit;231232static int check_hf_suport(void)233{234unsigned int eax = 0, ebx = 0, ecx = 0, edx = 0;235236__cpuid(6, eax, ebx, ecx, edx);237if (eax & BIT(19))238return 1;239240return 0;241}242243int hfi_main(void)244{245struct nl_sock *sock;246struct nl_cb *cb;247int err = 0;248int mcast_id;249250if (!check_hf_suport()) {251fprintf(stderr, "CPU Doesn't support HFI\n");252return -1;253}254255sock = nl_socket_alloc();256if (!sock) {257fprintf(stderr, "nl_socket_alloc failed\n");258return -1;259}260261if (genl_connect(sock)) {262fprintf(stderr, "genl_connect(sk_event) failed\n");263goto free_sock;264}265266drv.nl_handle = sock;267drv.nl_cb = cb = nl_cb_alloc(NL_CB_DEFAULT);268if (drv.nl_cb == NULL) {269printf("Failed to allocate netlink callbacks");270goto free_sock;271}272273mcast_id = nl_get_multicast_id(&drv, THERMAL_GENL_FAMILY_NAME,274THERMAL_GENL_EVENT_GROUP_NAME);275if (mcast_id < 0) {276fprintf(stderr, "nl_get_multicast_id failed\n");277goto free_sock;278}279280if (nl_socket_add_membership(sock, mcast_id)) {281fprintf(stderr, "nl_socket_add_membership failed");282goto free_sock;283}284285nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, seq_check_handler, 0);286nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, handle_event, NULL);287288debug_printf("hfi is initialized\n");289290while (!_hfi_exit && !err) {291err = nl_recvmsgs(sock, cb);292debug_printf("nl_recv_message err:%d\n", err);293}294295return 0;296297/* Netlink library doesn't have calls to dealloc cb or disconnect */298free_sock:299nl_socket_free(sock);300301return -1;302}303304void hfi_exit(void)305{306_hfi_exit = 1;307}308309310