Skip to content

Commit f2d2946

Browse files
multics69rafaeljw
authored andcommitted
PM: EM: Implement em_nl_get_pd_table_doit()
When a userspace requests EM_CMD_GET_PD_TABLE with an ID of a performance domain, the kernel reports back the energy model table of the specified performance domain. The message format of the response is as follows: EM_A_PD_TABLE_PD_ID (NLA_U32) EM_A_PD_TABLE_PS (NLA_NESTED)* EM_A_PS_PERFORMANCE (NLA_U64) EM_A_PS_FREQUENCY (NLA_U64) EM_A_PS_POWER (NLA_U64) EM_A_PS_COST (NLA_U64) EM_A_PS_FLAGS (NLA_U64) where EM_A_PD_TABLE_PS can be repeated as many times as there are performance states (struct em_perf_state). Signed-off-by: Changwoo Min <changwoo@igalia.com> Reviewed-by: Lukasz Luba <lukasz.luba@arm.com> Link: https://patch.msgid.link/20251020220914.320832-8-changwoo@igalia.com Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
1 parent d8eef04 commit f2d2946

1 file changed

Lines changed: 107 additions & 1 deletion

File tree

kernel/power/em_netlink.c

Lines changed: 107 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,115 @@ int em_nl_get_pds_doit(struct sk_buff *skb, struct genl_info *info)
102102
return ret;
103103
}
104104

105+
static struct em_perf_domain *__em_nl_get_pd_table_id(struct nlattr **attrs)
106+
{
107+
struct em_perf_domain *pd;
108+
int id;
109+
110+
if (!attrs[EM_A_PD_TABLE_PD_ID])
111+
return NULL;
112+
113+
id = nla_get_u32(attrs[EM_A_PD_TABLE_PD_ID]);
114+
pd = em_perf_domain_get_by_id(id);
115+
return pd;
116+
}
117+
118+
static int __em_nl_get_pd_table_size(const struct em_perf_domain *pd)
119+
{
120+
int id_sz, ps_sz;
121+
122+
id_sz = nla_total_size(sizeof(u32)); /* EM_A_PD_TABLE_PD_ID */
123+
ps_sz = nla_total_size(0) + /* EM_A_PD_TABLE_PS */
124+
nla_total_size_64bit(sizeof(u64)) + /* EM_A_PS_PERFORMANCE */
125+
nla_total_size_64bit(sizeof(u64)) + /* EM_A_PS_FREQUENCY */
126+
nla_total_size_64bit(sizeof(u64)) + /* EM_A_PS_POWER */
127+
nla_total_size_64bit(sizeof(u64)) + /* EM_A_PS_COST */
128+
nla_total_size_64bit(sizeof(u64)); /* EM_A_PS_FLAGS */
129+
ps_sz *= pd->nr_perf_states;
130+
131+
return nlmsg_total_size(genlmsg_msg_size(id_sz + ps_sz));
132+
}
133+
134+
static int __em_nl_get_pd_table(struct sk_buff *msg, const struct em_perf_domain *pd)
135+
{
136+
struct em_perf_state *table, *ps;
137+
struct nlattr *entry;
138+
int i;
139+
140+
if (nla_put_u32(msg, EM_A_PD_TABLE_PD_ID, pd->id))
141+
goto out_err;
142+
143+
rcu_read_lock();
144+
table = em_perf_state_from_pd((struct em_perf_domain *)pd);
145+
146+
for (i = 0; i < pd->nr_perf_states; i++) {
147+
ps = &table[i];
148+
149+
entry = nla_nest_start(msg, EM_A_PD_TABLE_PS);
150+
if (!entry)
151+
goto out_unlock_ps;
152+
153+
if (nla_put_u64_64bit(msg, EM_A_PS_PERFORMANCE,
154+
ps->performance, EM_A_PS_PAD))
155+
goto out_cancel_ps_nest;
156+
if (nla_put_u64_64bit(msg, EM_A_PS_FREQUENCY,
157+
ps->frequency, EM_A_PS_PAD))
158+
goto out_cancel_ps_nest;
159+
if (nla_put_u64_64bit(msg, EM_A_PS_POWER,
160+
ps->power, EM_A_PS_PAD))
161+
goto out_cancel_ps_nest;
162+
if (nla_put_u64_64bit(msg, EM_A_PS_COST,
163+
ps->cost, EM_A_PS_PAD))
164+
goto out_cancel_ps_nest;
165+
if (nla_put_u64_64bit(msg, EM_A_PS_FLAGS,
166+
ps->flags, EM_A_PS_PAD))
167+
goto out_cancel_ps_nest;
168+
169+
nla_nest_end(msg, entry);
170+
}
171+
rcu_read_unlock();
172+
return 0;
173+
174+
out_cancel_ps_nest:
175+
nla_nest_cancel(msg, entry);
176+
out_unlock_ps:
177+
rcu_read_unlock();
178+
out_err:
179+
return -EMSGSIZE;
180+
}
181+
105182
int em_nl_get_pd_table_doit(struct sk_buff *skb, struct genl_info *info)
106183
{
107-
return -EOPNOTSUPP;
184+
int cmd = info->genlhdr->cmd;
185+
int msg_sz, ret = -EMSGSIZE;
186+
struct em_perf_domain *pd;
187+
struct sk_buff *msg;
188+
void *hdr;
189+
190+
pd = __em_nl_get_pd_table_id(info->attrs);
191+
if (!pd)
192+
return -EINVAL;
193+
194+
msg_sz = __em_nl_get_pd_table_size(pd);
195+
196+
msg = genlmsg_new(msg_sz, GFP_KERNEL);
197+
if (!msg)
198+
return -ENOMEM;
199+
200+
hdr = genlmsg_put_reply(msg, info, &em_nl_family, 0, cmd);
201+
if (!hdr)
202+
goto out_free_msg;
203+
204+
ret = __em_nl_get_pd_table(msg, pd);
205+
if (ret)
206+
goto out_free_msg;
207+
208+
genlmsg_end(msg, hdr);
209+
return genlmsg_reply(msg, info);
210+
211+
out_free_msg:
212+
nlmsg_free(msg);
213+
return ret;
108214
}
109215

110216
static int __init em_netlink_init(void)

0 commit comments

Comments
 (0)