Merge tag 'pm-6.19-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm

Pull power management fixes from Rafael Wysocki:
 "These fix an error path memory leak in the energy model management
  code, fix a kerneldoc comment in it, and fix and revamp the energy
  model YNL specification added recently along with the new energy model
  management netlink interface (that received feedback after being
  added):

   - Fix a memory leak in em_create_pd() error path (Malaya Kumar Rout)

   - Fix stale description of the cost field in struct em_perf_state to
     reflect the current code (Yaxiong Tian)

   - Fix and revamp the energy model YNL specification added recently
     along with the energy model netlink interface (Changwoo Min)"

* tag 'pm-6.19-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
  PM: EM: Add dump to get-perf-domains in the EM YNL spec
  PM: EM: Change cpus' type from string to u64 array in the EM YNL spec
  PM: EM: Rename em.yaml to dev-energymodel.yaml
  PM: EM: Fix yamllint warnings in the EM YNL spec
  PM: EM: Fix memory leak in em_create_pd() error path
  PM: EM: Fix incorrect description of the cost field in struct em_perf_state
This commit is contained in:
Linus Torvalds
2026-01-16 12:08:19 -08:00
10 changed files with 454 additions and 288 deletions

View File

@@ -0,0 +1,175 @@
# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
#
# Copyright (c) 2025 Valve Corporation.
#
---
name: dev-energymodel
doc: |
Energy model netlink interface to notify its changes.
protocol: genetlink
uapi-header: linux/dev_energymodel.h
definitions:
-
type: flags
name: perf-state-flags
entries:
-
name: perf-state-inefficient
doc: >-
The performance state is inefficient. There is in this perf-domain,
another performance state with a higher frequency but a lower or
equal power cost.
-
type: flags
name: perf-domain-flags
entries:
-
name: perf-domain-microwatts
doc: >-
The power values are in micro-Watts or some other scale.
-
name: perf-domain-skip-inefficiencies
doc: >-
Skip inefficient states when estimating energy consumption.
-
name: perf-domain-artificial
doc: >-
The power values are artificial and might be created by platform
missing real power information.
attribute-sets:
-
name: perf-domain
doc: >-
Information on a single performance domains.
attributes:
-
name: pad
type: pad
-
name: perf-domain-id
type: u32
doc: >-
A unique ID number for each performance domain.
-
name: flags
type: u64
doc: >-
Bitmask of performance domain flags.
enum: perf-domain-flags
-
name: cpus
type: u64
multi-attr: true
doc: >-
CPUs that belong to this performance domain.
-
name: perf-table
doc: >-
Performance states table.
attributes:
-
name: perf-domain-id
type: u32
doc: >-
A unique ID number for each performance domain.
-
name: perf-state
type: nest
nested-attributes: perf-state
multi-attr: true
-
name: perf-state
doc: >-
Performance state of a performance domain.
attributes:
-
name: pad
type: pad
-
name: performance
type: u64
doc: >-
CPU performance (capacity) at a given frequency.
-
name: frequency
type: u64
doc: >-
The frequency in KHz, for consistency with CPUFreq.
-
name: power
type: u64
doc: >-
The power consumed at this level (by 1 CPU or by a registered
device). It can be a total power: static and dynamic.
-
name: cost
type: u64
doc: >-
The cost coefficient associated with this level, used during energy
calculation. Equal to: power * max_frequency / frequency.
-
name: flags
type: u64
doc: >-
Bitmask of performance state flags.
enum: perf-state-flags
operations:
list:
-
name: get-perf-domains
attribute-set: perf-domain
doc: Get the list of information for all performance domains.
do:
request:
attributes:
- perf-domain-id
reply:
attributes: &perf-domain-attrs
- pad
- perf-domain-id
- flags
- cpus
dump:
reply:
attributes: *perf-domain-attrs
-
name: get-perf-table
attribute-set: perf-table
doc: Get the energy model table of a performance domain.
do:
request:
attributes:
- perf-domain-id
reply:
attributes:
- perf-domain-id
- perf-state
-
name: perf-domain-created
doc: A performance domain is created.
notify: get-perf-table
mcgrp: event
-
name: perf-domain-updated
doc: A performance domain is updated.
notify: get-perf-table
mcgrp: event
-
name: perf-domain-deleted
doc: A performance domain is deleted.
attribute-set: perf-table
event:
attributes:
- perf-domain-id
mcgrp: event
mcast-groups:
list:
-
name: event

View File

@@ -1,113 +0,0 @@
# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
name: em
doc: |
Energy model netlink interface to notify its changes.
protocol: genetlink
uapi-header: linux/energy_model.h
attribute-sets:
-
name: pds
attributes:
-
name: pd
type: nest
nested-attributes: pd
multi-attr: true
-
name: pd
attributes:
-
name: pad
type: pad
-
name: pd-id
type: u32
-
name: flags
type: u64
-
name: cpus
type: string
-
name: pd-table
attributes:
-
name: pd-id
type: u32
-
name: ps
type: nest
nested-attributes: ps
multi-attr: true
-
name: ps
attributes:
-
name: pad
type: pad
-
name: performance
type: u64
-
name: frequency
type: u64
-
name: power
type: u64
-
name: cost
type: u64
-
name: flags
type: u64
operations:
list:
-
name: get-pds
attribute-set: pds
doc: Get the list of information for all performance domains.
do:
reply:
attributes:
- pd
-
name: get-pd-table
attribute-set: pd-table
doc: Get the energy model table of a performance domain.
do:
request:
attributes:
- pd-id
reply:
attributes:
- pd-id
- ps
-
name: pd-created
doc: A performance domain is created.
notify: get-pd-table
mcgrp: event
-
name: pd-updated
doc: A performance domain is updated.
notify: get-pd-table
mcgrp: event
-
name: pd-deleted
doc: A performance domain is deleted.
attribute-set: pd-table
event:
attributes:
- pd-id
mcgrp: event
mcast-groups:
list:
-
name: event

View File

@@ -9304,12 +9304,12 @@ M: Lukasz Luba <lukasz.luba@arm.com>
M: "Rafael J. Wysocki" <rafael@kernel.org>
L: linux-pm@vger.kernel.org
S: Maintained
F: kernel/power/energy_model.c
F: include/linux/energy_model.h
F: Documentation/netlink/specs/dev-energymodel.yaml
F: Documentation/power/energy-model.rst
F: Documentation/netlink/specs/em.yaml
F: include/uapi/linux/energy_model.h
F: include/linux/energy_model.h
F: include/uapi/linux/dev_energymodel.h
F: kernel/power/em_netlink*.*
F: kernel/power/energy_model.c
EPAPR HYPERVISOR BYTE CHANNEL DEVICE DRIVER
M: Laurentiu Tudor <laurentiu.tudor@nxp.com>

View File

@@ -18,7 +18,7 @@
* @power: The power consumed at this level (by 1 CPU or by a registered
* device). It can be a total power: static and dynamic.
* @cost: The cost coefficient associated with this level, used during
* energy calculation. Equal to: power * max_frequency / frequency
* energy calculation. Equal to: 10 * power * max_frequency / frequency
* @flags: see "em_perf_state flags" description below.
*/
struct em_perf_state {

View File

@@ -0,0 +1,82 @@
/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
/* Do not edit directly, auto-generated from: */
/* Documentation/netlink/specs/dev-energymodel.yaml */
/* YNL-GEN uapi header */
/* To regenerate run: tools/net/ynl/ynl-regen.sh */
#ifndef _UAPI_LINUX_DEV_ENERGYMODEL_H
#define _UAPI_LINUX_DEV_ENERGYMODEL_H
#define DEV_ENERGYMODEL_FAMILY_NAME "dev-energymodel"
#define DEV_ENERGYMODEL_FAMILY_VERSION 1
/**
* enum dev_energymodel_perf_state_flags
* @DEV_ENERGYMODEL_PERF_STATE_FLAGS_PERF_STATE_INEFFICIENT: The performance
* state is inefficient. There is in this perf-domain, another performance
* state with a higher frequency but a lower or equal power cost.
*/
enum dev_energymodel_perf_state_flags {
DEV_ENERGYMODEL_PERF_STATE_FLAGS_PERF_STATE_INEFFICIENT = 1,
};
/**
* enum dev_energymodel_perf_domain_flags
* @DEV_ENERGYMODEL_PERF_DOMAIN_FLAGS_PERF_DOMAIN_MICROWATTS: The power values
* are in micro-Watts or some other scale.
* @DEV_ENERGYMODEL_PERF_DOMAIN_FLAGS_PERF_DOMAIN_SKIP_INEFFICIENCIES: Skip
* inefficient states when estimating energy consumption.
* @DEV_ENERGYMODEL_PERF_DOMAIN_FLAGS_PERF_DOMAIN_ARTIFICIAL: The power values
* are artificial and might be created by platform missing real power
* information.
*/
enum dev_energymodel_perf_domain_flags {
DEV_ENERGYMODEL_PERF_DOMAIN_FLAGS_PERF_DOMAIN_MICROWATTS = 1,
DEV_ENERGYMODEL_PERF_DOMAIN_FLAGS_PERF_DOMAIN_SKIP_INEFFICIENCIES = 2,
DEV_ENERGYMODEL_PERF_DOMAIN_FLAGS_PERF_DOMAIN_ARTIFICIAL = 4,
};
enum {
DEV_ENERGYMODEL_A_PERF_DOMAIN_PAD = 1,
DEV_ENERGYMODEL_A_PERF_DOMAIN_PERF_DOMAIN_ID,
DEV_ENERGYMODEL_A_PERF_DOMAIN_FLAGS,
DEV_ENERGYMODEL_A_PERF_DOMAIN_CPUS,
__DEV_ENERGYMODEL_A_PERF_DOMAIN_MAX,
DEV_ENERGYMODEL_A_PERF_DOMAIN_MAX = (__DEV_ENERGYMODEL_A_PERF_DOMAIN_MAX - 1)
};
enum {
DEV_ENERGYMODEL_A_PERF_TABLE_PERF_DOMAIN_ID = 1,
DEV_ENERGYMODEL_A_PERF_TABLE_PERF_STATE,
__DEV_ENERGYMODEL_A_PERF_TABLE_MAX,
DEV_ENERGYMODEL_A_PERF_TABLE_MAX = (__DEV_ENERGYMODEL_A_PERF_TABLE_MAX - 1)
};
enum {
DEV_ENERGYMODEL_A_PERF_STATE_PAD = 1,
DEV_ENERGYMODEL_A_PERF_STATE_PERFORMANCE,
DEV_ENERGYMODEL_A_PERF_STATE_FREQUENCY,
DEV_ENERGYMODEL_A_PERF_STATE_POWER,
DEV_ENERGYMODEL_A_PERF_STATE_COST,
DEV_ENERGYMODEL_A_PERF_STATE_FLAGS,
__DEV_ENERGYMODEL_A_PERF_STATE_MAX,
DEV_ENERGYMODEL_A_PERF_STATE_MAX = (__DEV_ENERGYMODEL_A_PERF_STATE_MAX - 1)
};
enum {
DEV_ENERGYMODEL_CMD_GET_PERF_DOMAINS = 1,
DEV_ENERGYMODEL_CMD_GET_PERF_TABLE,
DEV_ENERGYMODEL_CMD_PERF_DOMAIN_CREATED,
DEV_ENERGYMODEL_CMD_PERF_DOMAIN_UPDATED,
DEV_ENERGYMODEL_CMD_PERF_DOMAIN_DELETED,
__DEV_ENERGYMODEL_CMD_MAX,
DEV_ENERGYMODEL_CMD_MAX = (__DEV_ENERGYMODEL_CMD_MAX - 1)
};
#define DEV_ENERGYMODEL_MCGRP_EVENT "event"
#endif /* _UAPI_LINUX_DEV_ENERGYMODEL_H */

View File

@@ -1,63 +0,0 @@
/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
/* Do not edit directly, auto-generated from: */
/* Documentation/netlink/specs/em.yaml */
/* YNL-GEN uapi header */
/* To regenerate run: tools/net/ynl/ynl-regen.sh */
#ifndef _UAPI_LINUX_ENERGY_MODEL_H
#define _UAPI_LINUX_ENERGY_MODEL_H
#define EM_FAMILY_NAME "em"
#define EM_FAMILY_VERSION 1
enum {
EM_A_PDS_PD = 1,
__EM_A_PDS_MAX,
EM_A_PDS_MAX = (__EM_A_PDS_MAX - 1)
};
enum {
EM_A_PD_PAD = 1,
EM_A_PD_PD_ID,
EM_A_PD_FLAGS,
EM_A_PD_CPUS,
__EM_A_PD_MAX,
EM_A_PD_MAX = (__EM_A_PD_MAX - 1)
};
enum {
EM_A_PD_TABLE_PD_ID = 1,
EM_A_PD_TABLE_PS,
__EM_A_PD_TABLE_MAX,
EM_A_PD_TABLE_MAX = (__EM_A_PD_TABLE_MAX - 1)
};
enum {
EM_A_PS_PAD = 1,
EM_A_PS_PERFORMANCE,
EM_A_PS_FREQUENCY,
EM_A_PS_POWER,
EM_A_PS_COST,
EM_A_PS_FLAGS,
__EM_A_PS_MAX,
EM_A_PS_MAX = (__EM_A_PS_MAX - 1)
};
enum {
EM_CMD_GET_PDS = 1,
EM_CMD_GET_PD_TABLE,
EM_CMD_PD_CREATED,
EM_CMD_PD_UPDATED,
EM_CMD_PD_DELETED,
__EM_CMD_MAX,
EM_CMD_MAX = (__EM_CMD_MAX - 1)
};
#define EM_MCGRP_EVENT "event"
#endif /* _UAPI_LINUX_ENERGY_MODEL_H */

View File

@@ -12,27 +12,35 @@
#include <linux/energy_model.h>
#include <net/sock.h>
#include <net/genetlink.h>
#include <uapi/linux/energy_model.h>
#include <uapi/linux/dev_energymodel.h>
#include "em_netlink.h"
#include "em_netlink_autogen.h"
#define EM_A_PD_CPUS_LEN 256
/*************************** Command encoding ********************************/
struct dump_ctx {
int idx;
int start;
struct sk_buff *skb;
struct netlink_callback *cb;
};
static int __em_nl_get_pd_size(struct em_perf_domain *pd, void *data)
{
char cpus_buf[EM_A_PD_CPUS_LEN];
int nr_cpus, msg_sz, cpus_sz;
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)));
nr_cpus = cpumask_weight(to_cpumask(pd->cpus));
cpus_sz = nla_total_size_64bit(sizeof(u64)) * nr_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 */
msg_sz = nla_total_size(0) +
/* DEV_ENERGYMODEL_A_PERF_DOMAINS_PERF_DOMAIN */
nla_total_size(sizeof(u32)) +
/* DEV_ENERGYMODEL_A_PERF_DOMAIN_PERF_DOMAIN_ID */
nla_total_size_64bit(sizeof(u64)) +
/* DEV_ENERGYMODEL_A_PERF_DOMAIN_FLAGS */
nla_total_size(cpus_sz);
/* DEV_ENERGYMODEL_A_PERF_DOMAIN_CPUS */
*tot_msg_sz += nlmsg_total_size(genlmsg_msg_size(msg_sz));
return 0;
@@ -40,56 +48,80 @@ static int __em_nl_get_pd_size(struct em_perf_domain *pd, void *data)
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;
struct cpumask *cpumask;
int cpu;
entry = nla_nest_start(msg, EM_A_PDS_PD);
if (!entry)
if (nla_put_u32(msg, DEV_ENERGYMODEL_A_PERF_DOMAIN_PERF_DOMAIN_ID,
pd->id))
goto out_cancel_nest;
if (nla_put_u32(msg, EM_A_PD_PD_ID, pd->id))
if (nla_put_u64_64bit(msg, DEV_ENERGYMODEL_A_PERF_DOMAIN_FLAGS,
pd->flags, DEV_ENERGYMODEL_A_PERF_DOMAIN_PAD))
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);
cpumask = to_cpumask(pd->cpus);
for_each_cpu(cpu, cpumask) {
if (nla_put_u64_64bit(msg, DEV_ENERGYMODEL_A_PERF_DOMAIN_CPUS,
cpu, DEV_ENERGYMODEL_A_PERF_DOMAIN_PAD))
goto out_cancel_nest;
}
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)
static int __em_nl_get_pd_for_dump(struct em_perf_domain *pd, void *data)
{
const struct genl_info *info;
struct dump_ctx *ctx = data;
void *hdr;
int ret;
if (ctx->idx++ < ctx->start)
return 0;
info = genl_info_dump(ctx->cb);
hdr = genlmsg_iput(ctx->skb, info);
if (!hdr) {
genlmsg_cancel(ctx->skb, hdr);
return -EMSGSIZE;
}
ret = __em_nl_get_pd(pd, ctx->skb);
genlmsg_end(ctx->skb, hdr);
return ret;
}
int dev_energymodel_nl_get_perf_domains_doit(struct sk_buff *skb,
struct genl_info *info)
{
int id, ret = -EMSGSIZE, msg_sz = 0;
int cmd = info->genlhdr->cmd;
struct em_perf_domain *pd;
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);
if (!info->attrs[DEV_ENERGYMODEL_A_PERF_DOMAIN_PERF_DOMAIN_ID])
return -EINVAL;
id = nla_get_u32(info->attrs[DEV_ENERGYMODEL_A_PERF_DOMAIN_PERF_DOMAIN_ID]);
pd = em_perf_domain_get_by_id(id);
__em_nl_get_pd_size(pd, &msg_sz);
msg = genlmsg_new(msg_sz, GFP_KERNEL);
if (!msg)
return -ENOMEM;
hdr = genlmsg_put_reply(msg, info, &em_nl_family, 0, cmd);
hdr = genlmsg_put_reply(msg, info, &dev_energymodel_nl_family, 0, cmd);
if (!hdr)
goto out_free_msg;
ret = for_each_em_perf_domain(__em_nl_get_pd, msg);
ret = __em_nl_get_pd(pd, msg);
if (ret)
goto out_cancel_msg;
genlmsg_end(msg, hdr);
return genlmsg_reply(msg, info);
@@ -98,19 +130,31 @@ out_cancel_msg:
genlmsg_cancel(msg, hdr);
out_free_msg:
nlmsg_free(msg);
return ret;
}
int dev_energymodel_nl_get_perf_domains_dumpit(struct sk_buff *skb,
struct netlink_callback *cb)
{
struct dump_ctx ctx = {
.idx = 0,
.start = cb->args[0],
.skb = skb,
.cb = cb,
};
return for_each_em_perf_domain(__em_nl_get_pd_for_dump, &ctx);
}
static struct em_perf_domain *__em_nl_get_pd_table_id(struct nlattr **attrs)
{
struct em_perf_domain *pd;
int id;
if (!attrs[EM_A_PD_TABLE_PD_ID])
if (!attrs[DEV_ENERGYMODEL_A_PERF_TABLE_PERF_DOMAIN_ID])
return NULL;
id = nla_get_u32(attrs[EM_A_PD_TABLE_PD_ID]);
id = nla_get_u32(attrs[DEV_ENERGYMODEL_A_PERF_TABLE_PERF_DOMAIN_ID]);
pd = em_perf_domain_get_by_id(id);
return pd;
}
@@ -119,25 +163,34 @@ static int __em_nl_get_pd_table_size(const struct em_perf_domain *pd)
{
int id_sz, ps_sz;
id_sz = nla_total_size(sizeof(u32)); /* EM_A_PD_TABLE_PD_ID */
ps_sz = nla_total_size(0) + /* EM_A_PD_TABLE_PS */
nla_total_size_64bit(sizeof(u64)) + /* EM_A_PS_PERFORMANCE */
nla_total_size_64bit(sizeof(u64)) + /* EM_A_PS_FREQUENCY */
nla_total_size_64bit(sizeof(u64)) + /* EM_A_PS_POWER */
nla_total_size_64bit(sizeof(u64)) + /* EM_A_PS_COST */
nla_total_size_64bit(sizeof(u64)); /* EM_A_PS_FLAGS */
id_sz = nla_total_size(sizeof(u32));
/* DEV_ENERGYMODEL_A_PERF_TABLE_PERF_DOMAIN_ID */
ps_sz = nla_total_size(0) +
/* DEV_ENERGYMODEL_A_PERF_TABLE_PERF_STATE */
nla_total_size_64bit(sizeof(u64)) +
/* DEV_ENERGYMODEL_A_PERF_STATE_PERFORMANCE */
nla_total_size_64bit(sizeof(u64)) +
/* DEV_ENERGYMODEL_A_PERF_STATE_FREQUENCY */
nla_total_size_64bit(sizeof(u64)) +
/* DEV_ENERGYMODEL_A_PERF_STATE_POWER */
nla_total_size_64bit(sizeof(u64)) +
/* DEV_ENERGYMODEL_A_PERF_STATE_COST */
nla_total_size_64bit(sizeof(u64));
/* DEV_ENERGYMODEL_A_PERF_STATE_FLAGS */
ps_sz *= pd->nr_perf_states;
return nlmsg_total_size(genlmsg_msg_size(id_sz + ps_sz));
}
static int __em_nl_get_pd_table(struct sk_buff *msg, const struct em_perf_domain *pd)
static
int __em_nl_get_pd_table(struct sk_buff *msg, const struct em_perf_domain *pd)
{
struct em_perf_state *table, *ps;
struct nlattr *entry;
int i;
if (nla_put_u32(msg, EM_A_PD_TABLE_PD_ID, pd->id))
if (nla_put_u32(msg, DEV_ENERGYMODEL_A_PERF_TABLE_PERF_DOMAIN_ID,
pd->id))
goto out_err;
rcu_read_lock();
@@ -146,24 +199,35 @@ static int __em_nl_get_pd_table(struct sk_buff *msg, const struct em_perf_domain
for (i = 0; i < pd->nr_perf_states; i++) {
ps = &table[i];
entry = nla_nest_start(msg, EM_A_PD_TABLE_PS);
entry = nla_nest_start(msg,
DEV_ENERGYMODEL_A_PERF_TABLE_PERF_STATE);
if (!entry)
goto out_unlock_ps;
if (nla_put_u64_64bit(msg, EM_A_PS_PERFORMANCE,
ps->performance, EM_A_PS_PAD))
if (nla_put_u64_64bit(msg,
DEV_ENERGYMODEL_A_PERF_STATE_PERFORMANCE,
ps->performance,
DEV_ENERGYMODEL_A_PERF_STATE_PAD))
goto out_cancel_ps_nest;
if (nla_put_u64_64bit(msg, EM_A_PS_FREQUENCY,
ps->frequency, EM_A_PS_PAD))
if (nla_put_u64_64bit(msg,
DEV_ENERGYMODEL_A_PERF_STATE_FREQUENCY,
ps->frequency,
DEV_ENERGYMODEL_A_PERF_STATE_PAD))
goto out_cancel_ps_nest;
if (nla_put_u64_64bit(msg, EM_A_PS_POWER,
ps->power, EM_A_PS_PAD))
if (nla_put_u64_64bit(msg,
DEV_ENERGYMODEL_A_PERF_STATE_POWER,
ps->power,
DEV_ENERGYMODEL_A_PERF_STATE_PAD))
goto out_cancel_ps_nest;
if (nla_put_u64_64bit(msg, EM_A_PS_COST,
ps->cost, EM_A_PS_PAD))
if (nla_put_u64_64bit(msg,
DEV_ENERGYMODEL_A_PERF_STATE_COST,
ps->cost,
DEV_ENERGYMODEL_A_PERF_STATE_PAD))
goto out_cancel_ps_nest;
if (nla_put_u64_64bit(msg, EM_A_PS_FLAGS,
ps->flags, EM_A_PS_PAD))
if (nla_put_u64_64bit(msg,
DEV_ENERGYMODEL_A_PERF_STATE_FLAGS,
ps->flags,
DEV_ENERGYMODEL_A_PERF_STATE_PAD))
goto out_cancel_ps_nest;
nla_nest_end(msg, entry);
@@ -179,7 +243,8 @@ out_err:
return -EMSGSIZE;
}
int em_nl_get_pd_table_doit(struct sk_buff *skb, struct genl_info *info)
int dev_energymodel_nl_get_perf_table_doit(struct sk_buff *skb,
struct genl_info *info)
{
int cmd = info->genlhdr->cmd;
int msg_sz, ret = -EMSGSIZE;
@@ -197,7 +262,7 @@ int em_nl_get_pd_table_doit(struct sk_buff *skb, struct genl_info *info)
if (!msg)
return -ENOMEM;
hdr = genlmsg_put_reply(msg, info, &em_nl_family, 0, cmd);
hdr = genlmsg_put_reply(msg, info, &dev_energymodel_nl_family, 0, cmd);
if (!hdr)
goto out_free_msg;
@@ -221,7 +286,7 @@ static void __em_notify_pd_table(const struct em_perf_domain *pd, int ntf_type)
int msg_sz, ret = -EMSGSIZE;
void *hdr;
if (!genl_has_listeners(&em_nl_family, &init_net, EM_NLGRP_EVENT))
if (!genl_has_listeners(&dev_energymodel_nl_family, &init_net, DEV_ENERGYMODEL_NLGRP_EVENT))
return;
msg_sz = __em_nl_get_pd_table_size(pd);
@@ -230,7 +295,7 @@ static void __em_notify_pd_table(const struct em_perf_domain *pd, int ntf_type)
if (!msg)
return;
hdr = genlmsg_put(msg, 0, 0, &em_nl_family, 0, ntf_type);
hdr = genlmsg_put(msg, 0, 0, &dev_energymodel_nl_family, 0, ntf_type);
if (!hdr)
goto out_free_msg;
@@ -240,28 +305,28 @@ static void __em_notify_pd_table(const struct em_perf_domain *pd, int ntf_type)
genlmsg_end(msg, hdr);
genlmsg_multicast(&em_nl_family, msg, 0, EM_NLGRP_EVENT, GFP_KERNEL);
genlmsg_multicast(&dev_energymodel_nl_family, msg, 0,
DEV_ENERGYMODEL_NLGRP_EVENT, GFP_KERNEL);
return;
out_free_msg:
nlmsg_free(msg);
return;
}
void em_notify_pd_created(const struct em_perf_domain *pd)
{
__em_notify_pd_table(pd, EM_CMD_PD_CREATED);
__em_notify_pd_table(pd, DEV_ENERGYMODEL_CMD_PERF_DOMAIN_CREATED);
}
void em_notify_pd_updated(const struct em_perf_domain *pd)
{
__em_notify_pd_table(pd, EM_CMD_PD_UPDATED);
__em_notify_pd_table(pd, DEV_ENERGYMODEL_CMD_PERF_DOMAIN_UPDATED);
}
static int __em_notify_pd_deleted_size(const struct em_perf_domain *pd)
{
int id_sz = nla_total_size(sizeof(u32)); /* EM_A_PD_TABLE_PD_ID */
int id_sz = nla_total_size(sizeof(u32)); /* DEV_ENERGYMODEL_A_PERF_TABLE_PERF_DOMAIN_ID */
return nlmsg_total_size(genlmsg_msg_size(id_sz));
}
@@ -272,7 +337,8 @@ void em_notify_pd_deleted(const struct em_perf_domain *pd)
void *hdr;
int msg_sz;
if (!genl_has_listeners(&em_nl_family, &init_net, EM_NLGRP_EVENT))
if (!genl_has_listeners(&dev_energymodel_nl_family, &init_net,
DEV_ENERGYMODEL_NLGRP_EVENT))
return;
msg_sz = __em_notify_pd_deleted_size(pd);
@@ -281,28 +347,29 @@ void em_notify_pd_deleted(const struct em_perf_domain *pd)
if (!msg)
return;
hdr = genlmsg_put(msg, 0, 0, &em_nl_family, 0, EM_CMD_PD_DELETED);
hdr = genlmsg_put(msg, 0, 0, &dev_energymodel_nl_family, 0,
DEV_ENERGYMODEL_CMD_PERF_DOMAIN_DELETED);
if (!hdr)
goto out_free_msg;
if (nla_put_u32(msg, EM_A_PD_TABLE_PD_ID, pd->id)) {
if (nla_put_u32(msg, DEV_ENERGYMODEL_A_PERF_TABLE_PERF_DOMAIN_ID,
pd->id))
goto out_free_msg;
}
genlmsg_end(msg, hdr);
genlmsg_multicast(&em_nl_family, msg, 0, EM_NLGRP_EVENT, GFP_KERNEL);
genlmsg_multicast(&dev_energymodel_nl_family, msg, 0,
DEV_ENERGYMODEL_NLGRP_EVENT, GFP_KERNEL);
return;
out_free_msg:
nlmsg_free(msg);
return;
}
/**************************** Initialization *********************************/
static int __init em_netlink_init(void)
{
return genl_register_family(&em_nl_family);
return genl_register_family(&dev_energymodel_nl_family);
}
postcore_initcall(em_netlink_init);

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
/* Do not edit directly, auto-generated from: */
/* Documentation/netlink/specs/em.yaml */
/* Documentation/netlink/specs/dev-energymodel.yaml */
/* YNL-GEN kernel source */
/* To regenerate run: tools/net/ynl/ynl-regen.sh */
@@ -9,41 +9,53 @@
#include "em_netlink_autogen.h"
#include <uapi/linux/energy_model.h>
#include <uapi/linux/dev_energymodel.h>
/* EM_CMD_GET_PD_TABLE - do */
static const struct nla_policy em_get_pd_table_nl_policy[EM_A_PD_TABLE_PD_ID + 1] = {
[EM_A_PD_TABLE_PD_ID] = { .type = NLA_U32, },
/* DEV_ENERGYMODEL_CMD_GET_PERF_DOMAINS - do */
static const struct nla_policy dev_energymodel_get_perf_domains_nl_policy[DEV_ENERGYMODEL_A_PERF_DOMAIN_PERF_DOMAIN_ID + 1] = {
[DEV_ENERGYMODEL_A_PERF_DOMAIN_PERF_DOMAIN_ID] = { .type = NLA_U32, },
};
/* Ops table for em */
static const struct genl_split_ops em_nl_ops[] = {
/* DEV_ENERGYMODEL_CMD_GET_PERF_TABLE - do */
static const struct nla_policy dev_energymodel_get_perf_table_nl_policy[DEV_ENERGYMODEL_A_PERF_TABLE_PERF_DOMAIN_ID + 1] = {
[DEV_ENERGYMODEL_A_PERF_TABLE_PERF_DOMAIN_ID] = { .type = NLA_U32, },
};
/* Ops table for dev_energymodel */
static const struct genl_split_ops dev_energymodel_nl_ops[] = {
{
.cmd = EM_CMD_GET_PDS,
.doit = em_nl_get_pds_doit,
.flags = GENL_CMD_CAP_DO,
.cmd = DEV_ENERGYMODEL_CMD_GET_PERF_DOMAINS,
.doit = dev_energymodel_nl_get_perf_domains_doit,
.policy = dev_energymodel_get_perf_domains_nl_policy,
.maxattr = DEV_ENERGYMODEL_A_PERF_DOMAIN_PERF_DOMAIN_ID,
.flags = GENL_CMD_CAP_DO,
},
{
.cmd = EM_CMD_GET_PD_TABLE,
.doit = em_nl_get_pd_table_doit,
.policy = em_get_pd_table_nl_policy,
.maxattr = EM_A_PD_TABLE_PD_ID,
.cmd = DEV_ENERGYMODEL_CMD_GET_PERF_DOMAINS,
.dumpit = dev_energymodel_nl_get_perf_domains_dumpit,
.flags = GENL_CMD_CAP_DUMP,
},
{
.cmd = DEV_ENERGYMODEL_CMD_GET_PERF_TABLE,
.doit = dev_energymodel_nl_get_perf_table_doit,
.policy = dev_energymodel_get_perf_table_nl_policy,
.maxattr = DEV_ENERGYMODEL_A_PERF_TABLE_PERF_DOMAIN_ID,
.flags = GENL_CMD_CAP_DO,
},
};
static const struct genl_multicast_group em_nl_mcgrps[] = {
[EM_NLGRP_EVENT] = { "event", },
static const struct genl_multicast_group dev_energymodel_nl_mcgrps[] = {
[DEV_ENERGYMODEL_NLGRP_EVENT] = { "event", },
};
struct genl_family em_nl_family __ro_after_init = {
.name = EM_FAMILY_NAME,
.version = EM_FAMILY_VERSION,
struct genl_family dev_energymodel_nl_family __ro_after_init = {
.name = DEV_ENERGYMODEL_FAMILY_NAME,
.version = DEV_ENERGYMODEL_FAMILY_VERSION,
.netnsok = true,
.parallel_ops = true,
.module = THIS_MODULE,
.split_ops = em_nl_ops,
.n_split_ops = ARRAY_SIZE(em_nl_ops),
.mcgrps = em_nl_mcgrps,
.n_mcgrps = ARRAY_SIZE(em_nl_mcgrps),
.split_ops = dev_energymodel_nl_ops,
.n_split_ops = ARRAY_SIZE(dev_energymodel_nl_ops),
.mcgrps = dev_energymodel_nl_mcgrps,
.n_mcgrps = ARRAY_SIZE(dev_energymodel_nl_mcgrps),
};

View File

@@ -1,24 +1,28 @@
/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
/* Do not edit directly, auto-generated from: */
/* Documentation/netlink/specs/em.yaml */
/* Documentation/netlink/specs/dev-energymodel.yaml */
/* YNL-GEN kernel header */
/* To regenerate run: tools/net/ynl/ynl-regen.sh */
#ifndef _LINUX_EM_GEN_H
#define _LINUX_EM_GEN_H
#ifndef _LINUX_DEV_ENERGYMODEL_GEN_H
#define _LINUX_DEV_ENERGYMODEL_GEN_H
#include <net/netlink.h>
#include <net/genetlink.h>
#include <uapi/linux/energy_model.h>
#include <uapi/linux/dev_energymodel.h>
int em_nl_get_pds_doit(struct sk_buff *skb, struct genl_info *info);
int em_nl_get_pd_table_doit(struct sk_buff *skb, struct genl_info *info);
int dev_energymodel_nl_get_perf_domains_doit(struct sk_buff *skb,
struct genl_info *info);
int dev_energymodel_nl_get_perf_domains_dumpit(struct sk_buff *skb,
struct netlink_callback *cb);
int dev_energymodel_nl_get_perf_table_doit(struct sk_buff *skb,
struct genl_info *info);
enum {
EM_NLGRP_EVENT,
DEV_ENERGYMODEL_NLGRP_EVENT,
};
extern struct genl_family em_nl_family;
extern struct genl_family dev_energymodel_nl_family;
#endif /* _LINUX_EM_GEN_H */
#endif /* _LINUX_DEV_ENERGYMODEL_GEN_H */

View File

@@ -449,8 +449,10 @@ static int em_create_pd(struct device *dev, int nr_states,
INIT_LIST_HEAD(&pd->node);
id = ida_alloc(&em_pd_ida, GFP_KERNEL);
if (id < 0)
return -ENOMEM;
if (id < 0) {
kfree(pd);
return id;
}
pd->id = id;
em_table = em_table_alloc(pd);