From: Changwoo Min Date: Mon, 20 Oct 2025 22:09:10 +0000 (+0900) Subject: PM: EM: Implement em_nl_get_pds_doit() X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d8eef0453132dc95354e4c7ae839815e679179c6;p=thirdparty%2Flinux.git PM: EM: Implement em_nl_get_pds_doit() When a userspace requests EM_CMD_GET_PDS, the kernel responds with information on all performance domains. The message format of the response is as follows: EM_A_PDS_PD (NLA_NESTED)* EM_A_PD_PD_ID (NLA_U32) EM_A_PD_FLAGS (NLA_U64) EM_A_PD_CPUS (NLA_STRING) where EM_A_PDS_PD can be repeated as many times as there are performance domains, and EM_A_PD_CPUS is a hexadecimal string representing a CPU bitmask. Signed-off-by: Changwoo Min Reviewed-by: Lukasz Luba Link: https://patch.msgid.link/20251020220914.320832-7-changwoo@igalia.com Signed-off-by: Rafael J. Wysocki --- diff --git a/kernel/power/em_netlink.c b/kernel/power/em_netlink.c index f8c98ae96aca0..16bdcf47f4d89 100644 --- a/kernel/power/em_netlink.c +++ b/kernel/power/em_netlink.c @@ -17,9 +17,89 @@ #include "em_netlink.h" #include "em_netlink_autogen.h" +#define EM_A_PD_CPUS_LEN 256 + +/*************************** Command encoding ********************************/ +static int __em_nl_get_pd_size(struct em_perf_domain *pd, void *data) +{ + char cpus_buf[EM_A_PD_CPUS_LEN]; + int *tot_msg_sz = data; + int msg_sz, cpus_sz; + + cpus_sz = snprintf(cpus_buf, sizeof(cpus_buf), "%*pb", + cpumask_pr_args(to_cpumask(pd->cpus))); + + msg_sz = nla_total_size(0) + /* EM_A_PDS_PD */ + nla_total_size(sizeof(u32)) + /* EM_A_PD_PD_ID */ + nla_total_size_64bit(sizeof(u64)) + /* EM_A_PD_FLAGS */ + nla_total_size(cpus_sz); /* EM_A_PD_CPUS */ + + *tot_msg_sz += nlmsg_total_size(genlmsg_msg_size(msg_sz)); + return 0; +} + +static int __em_nl_get_pd(struct em_perf_domain *pd, void *data) +{ + char cpus_buf[EM_A_PD_CPUS_LEN]; + struct sk_buff *msg = data; + struct nlattr *entry; + + entry = nla_nest_start(msg, EM_A_PDS_PD); + if (!entry) + goto out_cancel_nest; + + if (nla_put_u32(msg, EM_A_PD_PD_ID, pd->id)) + goto out_cancel_nest; + + if (nla_put_u64_64bit(msg, EM_A_PD_FLAGS, pd->flags, EM_A_PD_PAD)) + goto out_cancel_nest; + + snprintf(cpus_buf, sizeof(cpus_buf), "%*pb", + cpumask_pr_args(to_cpumask(pd->cpus))); + if (nla_put_string(msg, EM_A_PD_CPUS, cpus_buf)) + goto out_cancel_nest; + + nla_nest_end(msg, entry); + + return 0; + +out_cancel_nest: + nla_nest_cancel(msg, entry); + + return -EMSGSIZE; +} + int em_nl_get_pds_doit(struct sk_buff *skb, struct genl_info *info) { - return -EOPNOTSUPP; + struct sk_buff *msg; + void *hdr; + int cmd = info->genlhdr->cmd; + int ret = -EMSGSIZE, msg_sz = 0; + + for_each_em_perf_domain(__em_nl_get_pd_size, &msg_sz); + + msg = genlmsg_new(msg_sz, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + hdr = genlmsg_put_reply(msg, info, &em_nl_family, 0, cmd); + if (!hdr) + goto out_free_msg; + + ret = for_each_em_perf_domain(__em_nl_get_pd, msg); + if (ret) + goto out_cancel_msg; + + genlmsg_end(msg, hdr); + + return genlmsg_reply(msg, info); + +out_cancel_msg: + genlmsg_cancel(msg, hdr); +out_free_msg: + nlmsg_free(msg); + + return ret; } int em_nl_get_pd_table_doit(struct sk_buff *skb, struct genl_info *info)