Skip to contentSkip to conversation

acpi-cpufreq: replace per_cpu with driver_data of policy

PATCH In review Pan Xinhui 4 participants 9 messages Jul 7, 2015 – Jul 10, 2015 CPU frequency scaling framework

lore
Share & tools
lore

Pan Xinhui

author
#0 lore raw

PATCH v2 1/1 acpi-cpufreq: replace per_cpu with driver_data of policy

Drivers can store their internal per-policy information in policy->driver_data, lets use it.

we have benefits after this replacing.
1) memory saving.
2) policy is shared by several cpus, per_cpu seems not correct. using *driver_data* is more reasonable.
3) fix a memory leak in acpi_cpufreq_cpu_exit. as policy->cpu might change during cpu hotplug. So sometimes we cant't free *data*, use *driver_data* to fix it.
4) fix a zero return value of get_cur_freq_on_cpu. Only per_cpu of policy->cpu is set to *data*, if we try to get cpufreq on other cpus, we get zero instead of correct values. Use *driver_data* to fix it.

---
Changes from V1:
codes style fix, comments update
move cpufreq_cpu_put(policy) after we get *driver_data*

---
 drivers/cpufreq/acpi-cpufreq.c | 40 ++++++++++++++++++++++------------------
 1 file changed, 22 insertions(+), 18 deletions(-)
drivers/cpufreq/acpi-cpufreq.c +22 -18
index 0136dfc..e7fcaa6 100644
@@ -72,8 +72,6 @@ struct acpi_cpufreq_data {
 	cpumask_var_t freqdomain_cpus;
 };
 
-static DEFINE_PER_CPU(struct acpi_cpufreq_data *, acfreq_data);
-
 /* acpi_perf_data is a pointer to percpu data. */
 static struct acpi_processor_performance __percpu *acpi_perf_data;
 
@@ -144,7 +142,7 @@ static int _store_boost(int val)
 
 static ssize_t show_freqdomain_cpus(struct cpufreq_policy *policy, char *buf)
 {
-	struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu);
+	struct acpi_cpufreq_data *data = policy->driver_data;
 
 	return cpufreq_show_cpus(data->freqdomain_cpus, buf);
 }
@@ -327,7 +325,8 @@ static void drv_write(struct drv_cmd *cmd)
 	put_cpu();
 }
 
-static u32 get_cur_val(const struct cpumask *mask)
+static u32
+get_cur_val(const struct cpumask *mask, struct acpi_cpufreq_data *data)
 {
 	struct acpi_processor_performance *perf;
 	struct drv_cmd cmd;
@@ -335,7 +334,7 @@ static u32 get_cur_val(const struct cpumask *mask)
 	if (unlikely(cpumask_empty(mask)))
 		return 0;
 
-	switch (per_cpu(acfreq_data, cpumask_first(mask))->cpu_feature) {
+	switch (data->cpu_feature) {
 	case SYSTEM_INTEL_MSR_CAPABLE:
 		cmd.type = SYSTEM_INTEL_MSR_CAPABLE;
 		cmd.addr.msr.reg = MSR_IA32_PERF_CTL;
@@ -346,7 +345,7 @@ static u32 get_cur_val(const struct cpumask *mask)
 		break;
 	case SYSTEM_IO_CAPABLE:
 		cmd.type = SYSTEM_IO_CAPABLE;
-		perf = per_cpu(acfreq_data, cpumask_first(mask))->acpi_data;
+		perf = data->acpi_data;
 		cmd.addr.io.port = perf->control_register.address;
 		cmd.addr.io.bit_width = perf->control_register.bit_width;
 		break;
@@ -364,19 +363,24 @@ static u32 get_cur_val(const struct cpumask *mask)
 
 static unsigned int get_cur_freq_on_cpu(unsigned int cpu)
 {
-	struct acpi_cpufreq_data *data = per_cpu(acfreq_data, cpu);
+	struct acpi_cpufreq_data *data;
+	struct cpufreq_policy *policy;
 	unsigned int freq;
 	unsigned int cached_freq;
 
 	pr_debug("get_cur_freq_on_cpu (%d)\n", cpu);
 
-	if (unlikely(data == NULL ||
-		     data->acpi_data == NULL || data->freq_table == NULL)) {
+	policy = cpufreq_cpu_get(cpu);
+	if (unlikely(!policy))
+		return 0;
+
+	data = policy->driver_data;
+	cpufreq_cpu_put(policy);
+	if (unlikely(!data || !data->acpi_data || !data->freq_table))
 		return 0;
-	}
 
 	cached_freq = data->freq_table[data->acpi_data->state].frequency;
-	freq = extract_freq(get_cur_val(cpumask_of(cpu)), data);
+	freq = extract_freq(get_cur_val(cpumask_of(cpu), data), data);
 	if (freq != cached_freq) {
 		/*
 		 * The dreaded BIOS frequency change behind our back.
@@ -397,7 +401,7 @@ static unsigned int check_freqs(const struct cpumask *mask, unsigned int freq,
 	unsigned int i;
 
 	for (i = 0; i < 100; i++) {
-		cur_freq = extract_freq(get_cur_val(mask), data);
+		cur_freq = extract_freq(get_cur_val(mask, data), data);
 		if (cur_freq == freq)
 			return 1;
 		udelay(10);
@@ -408,7 +412,7 @@ static unsigned int check_freqs(const struct cpumask *mask, unsigned int freq,
 static int acpi_cpufreq_target(struct cpufreq_policy *policy,
 			       unsigned int index)
 {
-	struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu);
+	struct acpi_cpufreq_data *data = policy->driver_data;
 	struct acpi_processor_performance *perf;
 	struct drv_cmd cmd;
 	unsigned int next_perf_state = 0; /* Index into perf table */
@@ -673,7 +677,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
 	}
 
 	data->acpi_data = per_cpu_ptr(acpi_perf_data, cpu);
-	per_cpu(acfreq_data, cpu) = data;
+	policy->driver_data = data;
 
 	if (cpu_has(c, X86_FEATURE_CONSTANT_TSC))
 		acpi_cpufreq_driver.flags |= CPUFREQ_CONST_LOOPS;
@@ -843,19 +847,19 @@ err_free_mask:
 	free_cpumask_var(data->freqdomain_cpus);
 err_free:
 	kfree(data);
-	per_cpu(acfreq_data, cpu) = NULL;
+	policy->driver_data = NULL;
 
 	return result;
 }
 
 static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy)
 {
-	struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu);
+	struct acpi_cpufreq_data *data = policy->driver_data;
 
 	pr_debug("acpi_cpufreq_cpu_exit\n");
 
 	if (data) {
-		per_cpu(acfreq_data, policy->cpu) = NULL;
+		policy->driver_data = NULL;
 		acpi_processor_unregister_performance(data->acpi_data,
 						      policy->cpu);
 		free_cpumask_var(data->freqdomain_cpus);
@@ -868,7 +872,7 @@ static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy)
 
 static int acpi_cpufreq_resume(struct cpufreq_policy *policy)
 {
-	struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu);
+	struct acpi_cpufreq_data *data = policy->driver_data;
 
 	pr_debug("acpi_cpufreq_resume\n");
 
Signature · 1 line
1.9.1
author
#1 lore raw

hi, all
thanks for reviewing.
any comments or advices are welcome :)
I am OOO tomorrow, so response may arrive later.

thanks
xinhui

Quoted 164 lines · Pan Xinhui

Drivers can store their internal per-policy information in policy->driver_data, lets use it.

we have benefits after this replacing.
1) memory saving.
2) policy is shared by several cpus, per_cpu seems not correct. using *driver_data* is more reasonable.
3) fix a memory leak in acpi_cpufreq_cpu_exit. as policy->cpu might change during cpu hotplug. So sometimes we cant't free *data*, use *driver_data* to fix it.
4) fix a zero return value of get_cur_freq_on_cpu. Only per_cpu of policy->cpu is set to *data*, if we try to get cpufreq on other cpus, we get zero instead of correct values. Use *driver_data* to fix it.

---
Changes from V1:
codes style fix, comments update
move cpufreq_cpu_put(policy) after we get *driver_data*

---
 drivers/cpufreq/acpi-cpufreq.c | 40 ++++++++++++++++++++++------------------
 1 file changed, 22 insertions(+), 18 deletions(-)
drivers/cpufreq/acpi-cpufreq.c +22 -18
index 0136dfc..e7fcaa6 100644
@@ -72,8 +72,6 @@ struct acpi_cpufreq_data {
 	cpumask_var_t freqdomain_cpus;
 };
 
-static DEFINE_PER_CPU(struct acpi_cpufreq_data *, acfreq_data);
-
 /* acpi_perf_data is a pointer to percpu data. */
 static struct acpi_processor_performance __percpu *acpi_perf_data;
 
@@ -144,7 +142,7 @@ static int _store_boost(int val)
 
 static ssize_t show_freqdomain_cpus(struct cpufreq_policy *policy, char *buf)
 {
-	struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu);
+	struct acpi_cpufreq_data *data = policy->driver_data;
 
 	return cpufreq_show_cpus(data->freqdomain_cpus, buf);
 }
@@ -327,7 +325,8 @@ static void drv_write(struct drv_cmd *cmd)
 	put_cpu();
 }
 
-static u32 get_cur_val(const struct cpumask *mask)
+static u32
+get_cur_val(const struct cpumask *mask, struct acpi_cpufreq_data *data)
 {
 	struct acpi_processor_performance *perf;
 	struct drv_cmd cmd;
@@ -335,7 +334,7 @@ static u32 get_cur_val(const struct cpumask *mask)
 	if (unlikely(cpumask_empty(mask)))
 		return 0;
 
-	switch (per_cpu(acfreq_data, cpumask_first(mask))->cpu_feature) {
+	switch (data->cpu_feature) {
 	case SYSTEM_INTEL_MSR_CAPABLE:
 		cmd.type = SYSTEM_INTEL_MSR_CAPABLE;
 		cmd.addr.msr.reg = MSR_IA32_PERF_CTL;
@@ -346,7 +345,7 @@ static u32 get_cur_val(const struct cpumask *mask)
 		break;
 	case SYSTEM_IO_CAPABLE:
 		cmd.type = SYSTEM_IO_CAPABLE;
-		perf = per_cpu(acfreq_data, cpumask_first(mask))->acpi_data;
+		perf = data->acpi_data;
 		cmd.addr.io.port = perf->control_register.address;
 		cmd.addr.io.bit_width = perf->control_register.bit_width;
 		break;
@@ -364,19 +363,24 @@ static u32 get_cur_val(const struct cpumask *mask)
 
 static unsigned int get_cur_freq_on_cpu(unsigned int cpu)
 {
-	struct acpi_cpufreq_data *data = per_cpu(acfreq_data, cpu);
+	struct acpi_cpufreq_data *data;
+	struct cpufreq_policy *policy;
 	unsigned int freq;
 	unsigned int cached_freq;
 
 	pr_debug("get_cur_freq_on_cpu (%d)\n", cpu);
 
-	if (unlikely(data == NULL ||
-		     data->acpi_data == NULL || data->freq_table == NULL)) {
+	policy = cpufreq_cpu_get(cpu);
+	if (unlikely(!policy))
+		return 0;
+
+	data = policy->driver_data;
+	cpufreq_cpu_put(policy);
+	if (unlikely(!data || !data->acpi_data || !data->freq_table))
 		return 0;
-	}
 
 	cached_freq = data->freq_table[data->acpi_data->state].frequency;
-	freq = extract_freq(get_cur_val(cpumask_of(cpu)), data);
+	freq = extract_freq(get_cur_val(cpumask_of(cpu), data), data);
 	if (freq != cached_freq) {
 		/*
 		 * The dreaded BIOS frequency change behind our back.
@@ -397,7 +401,7 @@ static unsigned int check_freqs(const struct cpumask *mask, unsigned int freq,
 	unsigned int i;
 
 	for (i = 0; i < 100; i++) {
-		cur_freq = extract_freq(get_cur_val(mask), data);
+		cur_freq = extract_freq(get_cur_val(mask, data), data);
 		if (cur_freq == freq)
 			return 1;
 		udelay(10);
@@ -408,7 +412,7 @@ static unsigned int check_freqs(const struct cpumask *mask, unsigned int freq,
 static int acpi_cpufreq_target(struct cpufreq_policy *policy,
 			       unsigned int index)
 {
-	struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu);
+	struct acpi_cpufreq_data *data = policy->driver_data;
 	struct acpi_processor_performance *perf;
 	struct drv_cmd cmd;
 	unsigned int next_perf_state = 0; /* Index into perf table */
@@ -673,7 +677,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
 	}
 
 	data->acpi_data = per_cpu_ptr(acpi_perf_data, cpu);
-	per_cpu(acfreq_data, cpu) = data;
+	policy->driver_data = data;
 
 	if (cpu_has(c, X86_FEATURE_CONSTANT_TSC))
 		acpi_cpufreq_driver.flags |= CPUFREQ_CONST_LOOPS;
@@ -843,19 +847,19 @@ err_free_mask:
 	free_cpumask_var(data->freqdomain_cpus);
 err_free:
 	kfree(data);
-	per_cpu(acfreq_data, cpu) = NULL;
+	policy->driver_data = NULL;
 
 	return result;
 }
 
 static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy)
 {
-	struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu);
+	struct acpi_cpufreq_data *data = policy->driver_data;
 
 	pr_debug("acpi_cpufreq_cpu_exit\n");
 
 	if (data) {
-		per_cpu(acfreq_data, policy->cpu) = NULL;
+		policy->driver_data = NULL;
 		acpi_processor_unregister_performance(data->acpi_data,
 						      policy->cpu);
 		free_cpumask_var(data->freqdomain_cpus);
@@ -868,7 +872,7 @@ static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy)
 
 static int acpi_cpufreq_resume(struct cpufreq_policy *policy)
 {
-	struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu);
+	struct acpi_cpufreq_data *data = policy->driver_data;
 
 	pr_debug("acpi_cpufreq_resume\n");
 
maintainer Acked-by on v2 1/1
#2 lore raw
In reply to Pan Xinhui
Quoted 15 lines · Pan Xinhui

Drivers can store their internal per-policy information in policy->driver_data, lets use it.

we have benefits after this replacing.
1) memory saving.
2) policy is shared by several cpus, per_cpu seems not correct. using *driver_data* is more reasonable.
3) fix a memory leak in acpi_cpufreq_cpu_exit. as policy->cpu might change during cpu hotplug. So sometimes we cant't free *data*, use *driver_data* to fix it.
4) fix a zero return value of get_cur_freq_on_cpu. Only per_cpu of policy->cpu is set to *data*, if we try to get cpufreq on other cpus, we get zero instead of correct values. Use *driver_data* to fix it.

Quoted 8 lines

---
Changes from V1:
codes style fix, comments update
move cpufreq_cpu_put(policy) after we get *driver_data*

---
 drivers/cpufreq/acpi-cpufreq.c | 40 ++++++++++++++++++++++------------------
 1 file changed, 22 insertions(+), 18 deletions(-)
Signature · 1 line
viresh
#3 lore raw
Quoted 25 lines · Viresh Kumar
Quoted 15 lines · Pan Xinhui

Drivers can store their internal per-policy information in policy->driver_data, lets use it.

we have benefits after this replacing.
1) memory saving.
2) policy is shared by several cpus, per_cpu seems not correct. using *driver_data* is more reasonable.
3) fix a memory leak in acpi_cpufreq_cpu_exit. as policy->cpu might change during cpu hotplug. So sometimes we cant't free *data*, use *driver_data* to fix it.
4) fix a zero return value of get_cur_freq_on_cpu. Only per_cpu of policy->cpu is set to *data*, if we try to get cpufreq on other cpus, we get zero instead of correct values. Use *driver_data* to fix it.

Quoted 8 lines

---
Changes from V1:
codes style fix, comments update
move cpufreq_cpu_put(policy) after we get *driver_data*

---
 drivers/cpufreq/acpi-cpufreq.c | 40 ++++++++++++++++++++++------------------
 1 file changed, 22 insertions(+), 18 deletions(-)
Quoted 1 line

OK

Does it fix any recent regressions or is it just an old bug?

Rafael

author
#4 lore raw

hi, Rafael
thanks for your kind reply. :)

Quoted 26 lines · Rafael J. Wysocki
Quoted 25 lines · Viresh Kumar
Quoted 23 lines · Pan Xinhui

Drivers can store their internal per-policy information in policy->driver_data, lets use it.

we have benefits after this replacing.
1) memory saving.
2) policy is shared by several cpus, per_cpu seems not correct. using *driver_data* is more reasonable.
3) fix a memory leak in acpi_cpufreq_cpu_exit. as policy->cpu might change during cpu hotplug. So sometimes we cant't free *data*, use *driver_data* to fix it.
4) fix a zero return value of get_cur_freq_on_cpu. Only per_cpu of policy->cpu is set to *data*, if we try to get cpufreq on other cpus, we get zero instead of correct values. Use *driver_data* to fix it.

---
Changes from V1:
codes style fix, comments update
move cpufreq_cpu_put(policy) after we get *driver_data*

---
 drivers/cpufreq/acpi-cpufreq.c | 40 ++++++++++++++++++++++------------------
 1 file changed, 22 insertions(+), 18 deletions(-)
Quoted 6 lines
Quoted 1 line

OK

Does it fix any recent regressions or is it just an old bug?

This patch achieve old bug fix and codes improvements. In past days, policy has no field *driver_data*, So acpi-cpufreq driver has to use per_cpu to store some extra information. But it did not take good care of every scenarios. Now cpufreq core makes awesome effort to store more per-policy information in policy. We can make use of this feature. So I cook this patch. :)

I am preparing two patches for other two issues in acpi-cpufreq driver based on this patch. I will fix them step by step. :)

thanks
xinhui

Quoted 2 lines

Rafael

#5 lore raw
Quoted 34 lines · Pan Xinhui

hi, Rafael
thanks for your kind reply. :)

Quoted 30 lines · Rafael J. Wysocki
Quoted 25 lines · Viresh Kumar
Quoted 15 lines · Pan Xinhui

Drivers can store their internal per-policy information in policy->driver_data, lets use it.

we have benefits after this replacing.
1) memory saving.
2) policy is shared by several cpus, per_cpu seems not correct. using *driver_data* is more reasonable.
3) fix a memory leak in acpi_cpufreq_cpu_exit. as policy->cpu might change during cpu hotplug. So sometimes we cant't free *data*, use *driver_data* to fix it.
4) fix a zero return value of get_cur_freq_on_cpu. Only per_cpu of policy->cpu is set to *data*, if we try to get cpufreq on other cpus, we get zero instead of correct values. Use *driver_data* to fix it.

Quoted 8 lines

---
Changes from V1:
codes style fix, comments update
move cpufreq_cpu_put(policy) after we get *driver_data*

---
 drivers/cpufreq/acpi-cpufreq.c | 40 ++++++++++++++++++++++------------------
 1 file changed, 22 insertions(+), 18 deletions(-)
Quoted 1 line

OK

Quoted 7 lines
Quoted 2 lines

Does it fix any recent regressions or is it just an old bug?

This patch achieve old bug fix and codes improvements. In past days, policy has no field *driver_data*, So acpi-cpufreq driver has to use per_cpu to store some extra information. But it did not take good care of every scenarios. Now cpufreq core makes awesome effort to store more per-policy information in policy. We can make use of this feature. So I cook this patch. :)

OK, patch applied, thanks!

Quoted 2 lines

I am preparing two patches for other two issues in acpi-cpufreq driver based on this patch. I will fix them step by step. :)

Thanks for doing that!

Rafael

#6 lore raw
In reply to Pan Xinhui

Hi Pan,

Quoted 10 lines · Pan Xinhui
drivers/cpufreq/acpi-cpufreq.c +2 -1
@@ -364,19 +363,24 @@ static u32 get_cur_val(const struct cpumask *mask)
 
 static unsigned int get_cur_freq_on_cpu(unsigned int cpu)
 {
-	struct acpi_cpufreq_data *data = per_cpu(acfreq_data, cpu);
+	struct acpi_cpufreq_data *data;
+	struct cpufreq_policy *policy;
 	unsigned int freq;
 	unsigned int cached_freq;
 

drivers/cpufreq/acpi-cpufreq.c static u32 get_cur_val(const struct cpumask *mask) · line 378

Quoted 10 lines
drivers/cpufreq/acpi-cpufreq.c +6 -2
 	pr_debug("get_cur_freq_on_cpu (%d)\n", cpu);
 
-	if (unlikely(data == NULL ||
-		     data->acpi_data == NULL || data->freq_table == NULL)) {
+	policy = cpufreq_cpu_get(cpu);
+	if (unlikely(!policy))
+		return 0;
+
+	data = policy->driver_data;
+	cpufreq_cpu_put(policy);

If we put policy here can we guarantee that memory pointed to by data stays valid? Shoudln't we issue cpufreq_cpu_put(policy) after we done assessing the pointer?

drivers/cpufreq/acpi-cpufreq.c static u32 get_cur_val(const struct cpumask *mask) · line 386

Quoted 10 lines
drivers/cpufreq/acpi-cpufreq.c +2 -2
+	if (unlikely(!data || !data->acpi_data || !data->freq_table))
 		return 0;
-	}
 
 	cached_freq = data->freq_table[data->acpi_data->state].frequency;
-	freq = extract_freq(get_cur_val(cpumask_of(cpu)), data);
+	freq = extract_freq(get_cur_val(cpumask_of(cpu), data), data);
 	if (freq != cached_freq) {
 		/*
 		 * The dreaded BIOS frequency change behind our back.

Thanks.

Signature · 1 line
Dmitry
maintainer
#7 lore raw

Hi Dmitry,

Quoted 6 lines · Dmitry Torokhov

drivers/cpufreq/acpi-cpufreq.c static u32 get_cur_val(const struct cpumask *mask) · line 378

Quoted 2 lines
drivers/cpufreq/acpi-cpufreq.c +2 -0
+	data = policy->driver_data;
+	cpufreq_cpu_put(policy);

If we put policy here can we guarantee that memory pointed to by data stays valid? Shoudln't we issue cpufreq_cpu_put(policy) after we done assessing the pointer?

Ideally yes, you are right. But this was a special case as a callback of the cpufreq-driver is being called and any such issues must be handled at the core level, it at all they are relevant.

So probably we can do cpufreq_cpu_put() as soon as we have used it.

Signature · 1 line
viresh
author
#8 lore raw
In reply to Dmitry Torokhov

hi, Dmitry
thanks for your reply

Quoted 15 lines · Dmitry Torokhov

Hi Pan,

Quoted 12 lines · Pan Xinhui
drivers/cpufreq/acpi-cpufreq.c +2 -1
@@ -364,19 +363,24 @@ static u32 get_cur_val(const struct cpumask *mask)
 
 static unsigned int get_cur_freq_on_cpu(unsigned int cpu)
 {
-	struct acpi_cpufreq_data *data = per_cpu(acfreq_data, cpu);
+	struct acpi_cpufreq_data *data;
+	struct cpufreq_policy *policy;
 	unsigned int freq;
 	unsigned int cached_freq;
 
 	pr_debug("get_cur_freq_on_cpu (%d)\n", cpu);
 
Quoted 13 lines

drivers/cpufreq/acpi-cpufreq.c static u32 get_cur_val(const struct cpumask *mask) · line 378

Quoted 8 lines
drivers/cpufreq/acpi-cpufreq.c +6 -2
-	if (unlikely(data == NULL ||
-		     data->acpi_data == NULL || data->freq_table == NULL)) {
+	policy = cpufreq_cpu_get(cpu);
+	if (unlikely(!policy))
+		return 0;
+
+	data = policy->driver_data;
+	cpufreq_cpu_put(policy);

If we put policy here can we guarantee that memory pointed to by data stays valid? Shoudln't we issue cpufreq_cpu_put(policy) after we done assessing the pointer?

*driver_data* is used internal by acpi-cpufreq driver. So probably issuing cpufreq_cpu_put(policy) after we get *driver_data* is OKay.

The worry you have is about the race. we set *driver_data* to NULL then free it in ->exit callback while ->get callback is using it.

CPU A CPU B
->get ->exit
data = policy->driver_data;
if (!data ....)

					policy->driver_data = NULL;
					kfree(data);

access data ....

yes, it might happen in real world. As Viresh says, it is more like to be a core level work. But this race exists in current codes, too. Maybe down_write policy->rwsem can avoid this race(need double check).

thanks for pointing out it. :)

thanks
xinhui

Quoted 13 lines

drivers/cpufreq/acpi-cpufreq.c static u32 get_cur_val(const struct cpumask *mask) · line 386

Quoted 10 lines
drivers/cpufreq/acpi-cpufreq.c +2 -2
+	if (unlikely(!data || !data->acpi_data || !data->freq_table))
 		return 0;
-	}
 
 	cached_freq = data->freq_table[data->acpi_data->state].frequency;
-	freq = extract_freq(get_cur_val(cpumask_of(cpu)), data);
+	freq = extract_freq(get_cur_val(cpumask_of(cpu), data), data);
 	if (freq != cached_freq) {
 		/*
 		 * The dreaded BIOS frequency change behind our back.

Thanks.