Merge branch 'thermal-intel' into thermal
* thermal-intel: thermal: intel: int340x_thermal: replace deprecated strncpy() with strscpy() thermal: intel: hfi: Enable HFI only when required thermal: netlink: Rename thermal_gnl_family thermal: netlink: Add genetlink bind/unbind notifications
This commit is contained in:
commit
0dbf608717
@ -309,7 +309,7 @@ static int acpi_parse_psvt(acpi_handle handle, int *psvt_count, struct psvt **ps
|
||||
|
||||
if (knob->type == ACPI_TYPE_STRING) {
|
||||
memset(&psvt->limit, 0, sizeof(u64));
|
||||
strncpy(psvt->limit.string, psvt_ptr->limit.str_ptr, knob->string.length);
|
||||
strscpy(psvt->limit.string, psvt_ptr->limit.str_ptr, ACPI_LIMIT_STR_MAX_LEN);
|
||||
} else {
|
||||
psvt->limit.integer = psvt_ptr->limit.integer;
|
||||
}
|
||||
@ -468,7 +468,7 @@ static int fill_psvt(char __user *ubuf)
|
||||
psvt_user[i].unlimit_coeff = psvts[i].unlimit_coeff;
|
||||
psvt_user[i].control_knob_type = psvts[i].control_knob_type;
|
||||
if (psvt_user[i].control_knob_type == ACPI_TYPE_STRING)
|
||||
strncpy(psvt_user[i].limit.string, psvts[i].limit.string,
|
||||
strscpy(psvt_user[i].limit.string, psvts[i].limit.string,
|
||||
ACPI_LIMIT_STR_MAX_LEN);
|
||||
else
|
||||
psvt_user[i].limit.integer = psvts[i].limit.integer;
|
||||
|
@ -159,6 +159,7 @@ struct hfi_cpu_info {
|
||||
static DEFINE_PER_CPU(struct hfi_cpu_info, hfi_cpu_info) = { .index = -1 };
|
||||
|
||||
static int max_hfi_instances;
|
||||
static int hfi_clients_nr;
|
||||
static struct hfi_instance *hfi_instances;
|
||||
|
||||
static struct hfi_features hfi_features;
|
||||
@ -477,8 +478,11 @@ void intel_hfi_online(unsigned int cpu)
|
||||
enable:
|
||||
cpumask_set_cpu(cpu, hfi_instance->cpus);
|
||||
|
||||
/* Enable this HFI instance if this is its first online CPU. */
|
||||
if (cpumask_weight(hfi_instance->cpus) == 1) {
|
||||
/*
|
||||
* Enable this HFI instance if this is its first online CPU and
|
||||
* there are user-space clients of thermal events.
|
||||
*/
|
||||
if (cpumask_weight(hfi_instance->cpus) == 1 && hfi_clients_nr > 0) {
|
||||
hfi_set_hw_table(hfi_instance);
|
||||
hfi_enable();
|
||||
}
|
||||
@ -573,18 +577,33 @@ static __init int hfi_parse_features(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hfi_do_enable(void)
|
||||
/*
|
||||
* If concurrency is not prevented by other means, the HFI enable/disable
|
||||
* routines must be called under hfi_instance_lock."
|
||||
*/
|
||||
static void hfi_enable_instance(void *ptr)
|
||||
{
|
||||
hfi_set_hw_table(ptr);
|
||||
hfi_enable();
|
||||
}
|
||||
|
||||
static void hfi_disable_instance(void *ptr)
|
||||
{
|
||||
hfi_disable();
|
||||
}
|
||||
|
||||
static void hfi_syscore_resume(void)
|
||||
{
|
||||
/* This code runs only on the boot CPU. */
|
||||
struct hfi_cpu_info *info = &per_cpu(hfi_cpu_info, 0);
|
||||
struct hfi_instance *hfi_instance = info->hfi_instance;
|
||||
|
||||
/* No locking needed. There is no concurrency with CPU online. */
|
||||
hfi_set_hw_table(hfi_instance);
|
||||
hfi_enable();
|
||||
if (hfi_clients_nr > 0)
|
||||
hfi_enable_instance(hfi_instance);
|
||||
}
|
||||
|
||||
static int hfi_do_disable(void)
|
||||
static int hfi_syscore_suspend(void)
|
||||
{
|
||||
/* No locking needed. There is no concurrency with CPU offline. */
|
||||
hfi_disable();
|
||||
@ -593,8 +612,58 @@ static int hfi_do_disable(void)
|
||||
}
|
||||
|
||||
static struct syscore_ops hfi_pm_ops = {
|
||||
.resume = hfi_do_enable,
|
||||
.suspend = hfi_do_disable,
|
||||
.resume = hfi_syscore_resume,
|
||||
.suspend = hfi_syscore_suspend,
|
||||
};
|
||||
|
||||
static int hfi_thermal_notify(struct notifier_block *nb, unsigned long state,
|
||||
void *_notify)
|
||||
{
|
||||
struct thermal_genl_notify *notify = _notify;
|
||||
struct hfi_instance *hfi_instance;
|
||||
smp_call_func_t func = NULL;
|
||||
unsigned int cpu;
|
||||
int i;
|
||||
|
||||
if (notify->mcgrp != THERMAL_GENL_EVENT_GROUP)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
if (state != THERMAL_NOTIFY_BIND && state != THERMAL_NOTIFY_UNBIND)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
mutex_lock(&hfi_instance_lock);
|
||||
|
||||
switch (state) {
|
||||
case THERMAL_NOTIFY_BIND:
|
||||
if (++hfi_clients_nr == 1)
|
||||
func = hfi_enable_instance;
|
||||
break;
|
||||
case THERMAL_NOTIFY_UNBIND:
|
||||
if (--hfi_clients_nr == 0)
|
||||
func = hfi_disable_instance;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!func)
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < max_hfi_instances; i++) {
|
||||
hfi_instance = &hfi_instances[i];
|
||||
if (cpumask_empty(hfi_instance->cpus))
|
||||
continue;
|
||||
|
||||
cpu = cpumask_any(hfi_instance->cpus);
|
||||
smp_call_function_single(cpu, func, hfi_instance, true);
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&hfi_instance_lock);
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static struct notifier_block hfi_thermal_nb = {
|
||||
.notifier_call = hfi_thermal_notify,
|
||||
};
|
||||
|
||||
void __init intel_hfi_init(void)
|
||||
@ -628,10 +697,22 @@ void __init intel_hfi_init(void)
|
||||
if (!hfi_updates_wq)
|
||||
goto err_nomem;
|
||||
|
||||
/*
|
||||
* Both thermal core and Intel HFI can not be build as modules.
|
||||
* As kernel build-in drivers they are initialized before user-space
|
||||
* starts, hence we can not miss BIND/UNBIND events when applications
|
||||
* add/remove thermal multicast group to/from a netlink socket.
|
||||
*/
|
||||
if (thermal_genl_register_notifier(&hfi_thermal_nb))
|
||||
goto err_nl_notif;
|
||||
|
||||
register_syscore_ops(&hfi_pm_ops);
|
||||
|
||||
return;
|
||||
|
||||
err_nl_notif:
|
||||
destroy_workqueue(hfi_updates_wq);
|
||||
|
||||
err_nomem:
|
||||
for (j = 0; j < i; ++j) {
|
||||
hfi_instance = &hfi_instances[j];
|
||||
|
@ -7,17 +7,13 @@
|
||||
* Generic netlink for thermal management framework
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <net/genetlink.h>
|
||||
#include <uapi/linux/thermal.h>
|
||||
|
||||
#include "thermal_core.h"
|
||||
|
||||
enum thermal_genl_multicast_groups {
|
||||
THERMAL_GENL_SAMPLING_GROUP = 0,
|
||||
THERMAL_GENL_EVENT_GROUP = 1,
|
||||
};
|
||||
|
||||
static const struct genl_multicast_group thermal_genl_mcgrps[] = {
|
||||
[THERMAL_GENL_SAMPLING_GROUP] = { .name = THERMAL_GENL_SAMPLING_GROUP_NAME, },
|
||||
[THERMAL_GENL_EVENT_GROUP] = { .name = THERMAL_GENL_EVENT_GROUP_NAME, },
|
||||
@ -74,11 +70,12 @@ struct param {
|
||||
|
||||
typedef int (*cb_t)(struct param *);
|
||||
|
||||
static struct genl_family thermal_gnl_family;
|
||||
static struct genl_family thermal_genl_family;
|
||||
static BLOCKING_NOTIFIER_HEAD(thermal_genl_chain);
|
||||
|
||||
static int thermal_group_has_listeners(enum thermal_genl_multicast_groups group)
|
||||
{
|
||||
return genl_has_listeners(&thermal_gnl_family, &init_net, group);
|
||||
return genl_has_listeners(&thermal_genl_family, &init_net, group);
|
||||
}
|
||||
|
||||
/************************** Sampling encoding *******************************/
|
||||
@ -95,7 +92,7 @@ int thermal_genl_sampling_temp(int id, int temp)
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
hdr = genlmsg_put(skb, 0, 0, &thermal_gnl_family, 0,
|
||||
hdr = genlmsg_put(skb, 0, 0, &thermal_genl_family, 0,
|
||||
THERMAL_GENL_SAMPLING_TEMP);
|
||||
if (!hdr)
|
||||
goto out_free;
|
||||
@ -108,7 +105,7 @@ int thermal_genl_sampling_temp(int id, int temp)
|
||||
|
||||
genlmsg_end(skb, hdr);
|
||||
|
||||
genlmsg_multicast(&thermal_gnl_family, skb, 0, THERMAL_GENL_SAMPLING_GROUP, GFP_KERNEL);
|
||||
genlmsg_multicast(&thermal_genl_family, skb, 0, THERMAL_GENL_SAMPLING_GROUP, GFP_KERNEL);
|
||||
|
||||
return 0;
|
||||
out_cancel:
|
||||
@ -282,7 +279,7 @@ static int thermal_genl_send_event(enum thermal_genl_event event,
|
||||
return -ENOMEM;
|
||||
p->msg = msg;
|
||||
|
||||
hdr = genlmsg_put(msg, 0, 0, &thermal_gnl_family, 0, event);
|
||||
hdr = genlmsg_put(msg, 0, 0, &thermal_genl_family, 0, event);
|
||||
if (!hdr)
|
||||
goto out_free_msg;
|
||||
|
||||
@ -292,7 +289,7 @@ static int thermal_genl_send_event(enum thermal_genl_event event,
|
||||
|
||||
genlmsg_end(msg, hdr);
|
||||
|
||||
genlmsg_multicast(&thermal_gnl_family, msg, 0, THERMAL_GENL_EVENT_GROUP, GFP_KERNEL);
|
||||
genlmsg_multicast(&thermal_genl_family, msg, 0, THERMAL_GENL_EVENT_GROUP, GFP_KERNEL);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -595,7 +592,7 @@ static int thermal_genl_cmd_dumpit(struct sk_buff *skb,
|
||||
int ret;
|
||||
void *hdr;
|
||||
|
||||
hdr = genlmsg_put(skb, 0, 0, &thermal_gnl_family, 0, cmd);
|
||||
hdr = genlmsg_put(skb, 0, 0, &thermal_genl_family, 0, cmd);
|
||||
if (!hdr)
|
||||
return -EMSGSIZE;
|
||||
|
||||
@ -627,7 +624,7 @@ static int thermal_genl_cmd_doit(struct sk_buff *skb,
|
||||
return -ENOMEM;
|
||||
p.msg = msg;
|
||||
|
||||
hdr = genlmsg_put_reply(msg, info, &thermal_gnl_family, 0, cmd);
|
||||
hdr = genlmsg_put_reply(msg, info, &thermal_genl_family, 0, cmd);
|
||||
if (!hdr)
|
||||
goto out_free_msg;
|
||||
|
||||
@ -647,6 +644,27 @@ out_free_msg:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int thermal_genl_bind(int mcgrp)
|
||||
{
|
||||
struct thermal_genl_notify n = { .mcgrp = mcgrp };
|
||||
|
||||
if (WARN_ON_ONCE(mcgrp > THERMAL_GENL_MAX_GROUP))
|
||||
return -EINVAL;
|
||||
|
||||
blocking_notifier_call_chain(&thermal_genl_chain, THERMAL_NOTIFY_BIND, &n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void thermal_genl_unbind(int mcgrp)
|
||||
{
|
||||
struct thermal_genl_notify n = { .mcgrp = mcgrp };
|
||||
|
||||
if (WARN_ON_ONCE(mcgrp > THERMAL_GENL_MAX_GROUP))
|
||||
return;
|
||||
|
||||
blocking_notifier_call_chain(&thermal_genl_chain, THERMAL_NOTIFY_UNBIND, &n);
|
||||
}
|
||||
|
||||
static const struct genl_small_ops thermal_genl_ops[] = {
|
||||
{
|
||||
.cmd = THERMAL_GENL_CMD_TZ_GET_ID,
|
||||
@ -675,12 +693,14 @@ static const struct genl_small_ops thermal_genl_ops[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct genl_family thermal_gnl_family __ro_after_init = {
|
||||
static struct genl_family thermal_genl_family __ro_after_init = {
|
||||
.hdrsize = 0,
|
||||
.name = THERMAL_GENL_FAMILY_NAME,
|
||||
.version = THERMAL_GENL_VERSION,
|
||||
.maxattr = THERMAL_GENL_ATTR_MAX,
|
||||
.policy = thermal_genl_policy,
|
||||
.bind = thermal_genl_bind,
|
||||
.unbind = thermal_genl_unbind,
|
||||
.small_ops = thermal_genl_ops,
|
||||
.n_small_ops = ARRAY_SIZE(thermal_genl_ops),
|
||||
.resv_start_op = THERMAL_GENL_CMD_CDEV_GET + 1,
|
||||
@ -688,12 +708,22 @@ static struct genl_family thermal_gnl_family __ro_after_init = {
|
||||
.n_mcgrps = ARRAY_SIZE(thermal_genl_mcgrps),
|
||||
};
|
||||
|
||||
int thermal_genl_register_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return blocking_notifier_chain_register(&thermal_genl_chain, nb);
|
||||
}
|
||||
|
||||
int thermal_genl_unregister_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return blocking_notifier_chain_unregister(&thermal_genl_chain, nb);
|
||||
}
|
||||
|
||||
int __init thermal_netlink_init(void)
|
||||
{
|
||||
return genl_register_family(&thermal_gnl_family);
|
||||
return genl_register_family(&thermal_genl_family);
|
||||
}
|
||||
|
||||
void __init thermal_netlink_exit(void)
|
||||
{
|
||||
genl_unregister_family(&thermal_gnl_family);
|
||||
genl_unregister_family(&thermal_genl_family);
|
||||
}
|
||||
|
@ -10,6 +10,19 @@ struct thermal_genl_cpu_caps {
|
||||
int efficiency;
|
||||
};
|
||||
|
||||
enum thermal_genl_multicast_groups {
|
||||
THERMAL_GENL_SAMPLING_GROUP = 0,
|
||||
THERMAL_GENL_EVENT_GROUP = 1,
|
||||
THERMAL_GENL_MAX_GROUP = THERMAL_GENL_EVENT_GROUP,
|
||||
};
|
||||
|
||||
#define THERMAL_NOTIFY_BIND 0
|
||||
#define THERMAL_NOTIFY_UNBIND 1
|
||||
|
||||
struct thermal_genl_notify {
|
||||
int mcgrp;
|
||||
};
|
||||
|
||||
struct thermal_zone_device;
|
||||
struct thermal_trip;
|
||||
struct thermal_cooling_device;
|
||||
@ -18,6 +31,9 @@ struct thermal_cooling_device;
|
||||
#ifdef CONFIG_THERMAL_NETLINK
|
||||
int __init thermal_netlink_init(void);
|
||||
void __init thermal_netlink_exit(void);
|
||||
int thermal_genl_register_notifier(struct notifier_block *nb);
|
||||
int thermal_genl_unregister_notifier(struct notifier_block *nb);
|
||||
|
||||
int thermal_notify_tz_create(const struct thermal_zone_device *tz);
|
||||
int thermal_notify_tz_delete(const struct thermal_zone_device *tz);
|
||||
int thermal_notify_tz_enable(const struct thermal_zone_device *tz);
|
||||
@ -48,6 +64,16 @@ static inline int thermal_notify_tz_create(const struct thermal_zone_device *tz)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int thermal_genl_register_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int thermal_genl_unregister_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int thermal_notify_tz_delete(const struct thermal_zone_device *tz)
|
||||
{
|
||||
return 0;
|
||||
|
Loading…
Reference in New Issue
Block a user