[PATCH v1 1/2] enforce max/min time between commands

2015-11-16 Thread Zhang, Lin-Bao (Linux Kernel R)

In Processor Clocking Control specification v1.0 ,there are 2 definitions:
2.1.8 Minimum Time Between Commands
2.1.9 Maximum Time Between Commands
that means 2 commands' interval should be located between Minimum Time Between 
Commands and Maximum Time Between Commands.

3.1 Get Average Frequency
The Get Average Frequency command is used by the Operating System to query the 
running frequency of the processor since the last time this command was last 
completed.

This patch implements this feature, while old pcc-cpufreq.c didn't follow the 
rule.
Especially ,at boot time there will be no "last time" and BIOS can return out 
bounds frequencies including the value zero. 
In booting kernel case, we would run querying again as PCC spec.
In normal case, we also need to make sure these 2 commands interval is larger 
than Minimum Time Between Commands, and also smaller than the max time, 
although perhaps that is more rare.


Signed-off-by: Pearson, Greg 
Signed-off-by: Zhang, Lin-Bao 
---
 drivers/cpufreq/pcc-cpufreq.c | 39 ++-
 1 file changed, 38 insertions(+), 1 deletion(-)

diff --git a/drivers/cpufreq/pcc-cpufreq.c b/drivers/cpufreq/pcc-cpufreq.c
index 2a0d589..c8f1616 100644
--- a/drivers/cpufreq/pcc-cpufreq.c
+++ b/drivers/cpufreq/pcc-cpufreq.c
@@ -29,6 +29,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 #include 
 #include 

@@ -105,8 +107,12 @@ static u8 OSC_UUID[16] = {0x9F, 0x2C, 0x9B, 0x63, 0x91, 
0x70, 0x1f, 0x49,
 struct pcc_cpu {
u32 input_offset;
u32 output_offset;
+   u64 prev_time;
 };

+static u32 max_time_between_cmds = 0;
+static u32 min_time_between_cmds = 0;
+
 static struct pcc_cpu __percpu *pcc_cpu_info;

 static int pcc_cpufreq_verify(struct cpufreq_policy *policy)
@@ -137,7 +143,7 @@ static inline void pcc_clear_mapping(void)
pcch_virt_addr = NULL;
 }

-static unsigned int pcc_get_freq(unsigned int cpu)
+static unsigned int real_pcc_get_freq(unsigned int cpu)
 {
struct pcc_cpu *pcc_cpu_data;
unsigned int curr_freq;
@@ -185,6 +191,8 @@ static unsigned int pcc_get_freq(unsigned int cpu)
" capped at %d\n", cpu, curr_freq);
}

+   pcc_cpu_data->prev_time = get_jiffies_64();
+
spin_unlock(_lock);
return curr_freq;

@@ -194,6 +202,32 @@ cmd_incomplete:
return 0;
 }

+static unsigned int pcc_get_freq(unsigned int cpu)
+{
+   struct pcc_cpu *pcc_cpu_data;
+   unsigned int curr_freq;
+   u64 cur_time;
+   u32 diff_time;
+
+   pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu);
+   cur_time = get_jiffies_64();
+   diff_time = jiffies_to_usecs(cur_time - pcc_cpu_data->prev_time);
+
+   if (diff_time > max_time_between_cmds) {
+   curr_freq = real_pcc_get_freq(cpu);
+   cur_time = get_jiffies_64();
+   diff_time =
+   jiffies_to_usecs(cur_time - pcc_cpu_data->prev_time);
+   }
+
+   if (diff_time < min_time_between_cmds)
+   msleep((min_time_between_cmds - diff_time) / 1000);
+
+   curr_freq = real_pcc_get_freq(cpu);
+
+   return curr_freq;
+}
+
 static int pcc_cpufreq_target(struct cpufreq_policy *policy,
  unsigned int target_freq,
  unsigned int relation)
@@ -521,6 +555,9 @@ static int __init pcc_cpufreq_probe(void)
goto pcch_free;
}

+   max_time_between_cmds = ioread32(_hdr->maximum_time);
+   min_time_between_cmds = ioread32(_hdr->minimum_time);
+
printk(KERN_DEBUG "pcc-cpufreq: (v%s) driver loaded with frequency"
   " limits: %d MHz, %d MHz\n", PCC_VERSION,
   ioread32(_hdr->minimum_frequency),
--
1.8.5.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v1 1/2] enforce max/min time between commands

2015-11-16 Thread Zhang, Lin-Bao (Linux Kernel R)

In Processor Clocking Control specification v1.0 ,there are 2 definitions:
2.1.8 Minimum Time Between Commands
2.1.9 Maximum Time Between Commands
that means 2 commands' interval should be located between Minimum Time Between 
Commands and Maximum Time Between Commands.

3.1 Get Average Frequency
The Get Average Frequency command is used by the Operating System to query the 
running frequency of the processor since the last time this command was last 
completed.

This patch implements this feature, while old pcc-cpufreq.c didn't follow the 
rule.
Especially ,at boot time there will be no "last time" and BIOS can return out 
bounds frequencies including the value zero. 
In booting kernel case, we would run querying again as PCC spec.
In normal case, we also need to make sure these 2 commands interval is larger 
than Minimum Time Between Commands, and also smaller than the max time, 
although perhaps that is more rare.


Signed-off-by: Pearson, Greg 
Signed-off-by: Zhang, Lin-Bao 
---
 drivers/cpufreq/pcc-cpufreq.c | 39 ++-
 1 file changed, 38 insertions(+), 1 deletion(-)

diff --git a/drivers/cpufreq/pcc-cpufreq.c b/drivers/cpufreq/pcc-cpufreq.c
index 2a0d589..c8f1616 100644
--- a/drivers/cpufreq/pcc-cpufreq.c
+++ b/drivers/cpufreq/pcc-cpufreq.c
@@ -29,6 +29,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 #include 
 #include 

@@ -105,8 +107,12 @@ static u8 OSC_UUID[16] = {0x9F, 0x2C, 0x9B, 0x63, 0x91, 
0x70, 0x1f, 0x49,
 struct pcc_cpu {
u32 input_offset;
u32 output_offset;
+   u64 prev_time;
 };

+static u32 max_time_between_cmds = 0;
+static u32 min_time_between_cmds = 0;
+
 static struct pcc_cpu __percpu *pcc_cpu_info;

 static int pcc_cpufreq_verify(struct cpufreq_policy *policy)
@@ -137,7 +143,7 @@ static inline void pcc_clear_mapping(void)
pcch_virt_addr = NULL;
 }

-static unsigned int pcc_get_freq(unsigned int cpu)
+static unsigned int real_pcc_get_freq(unsigned int cpu)
 {
struct pcc_cpu *pcc_cpu_data;
unsigned int curr_freq;
@@ -185,6 +191,8 @@ static unsigned int pcc_get_freq(unsigned int cpu)
" capped at %d\n", cpu, curr_freq);
}

+   pcc_cpu_data->prev_time = get_jiffies_64();
+
spin_unlock(_lock);
return curr_freq;

@@ -194,6 +202,32 @@ cmd_incomplete:
return 0;
 }

+static unsigned int pcc_get_freq(unsigned int cpu)
+{
+   struct pcc_cpu *pcc_cpu_data;
+   unsigned int curr_freq;
+   u64 cur_time;
+   u32 diff_time;
+
+   pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu);
+   cur_time = get_jiffies_64();
+   diff_time = jiffies_to_usecs(cur_time - pcc_cpu_data->prev_time);
+
+   if (diff_time > max_time_between_cmds) {
+   curr_freq = real_pcc_get_freq(cpu);
+   cur_time = get_jiffies_64();
+   diff_time =
+   jiffies_to_usecs(cur_time - pcc_cpu_data->prev_time);
+   }
+
+   if (diff_time < min_time_between_cmds)
+   msleep((min_time_between_cmds - diff_time) / 1000);
+
+   curr_freq = real_pcc_get_freq(cpu);
+
+   return curr_freq;
+}
+
 static int pcc_cpufreq_target(struct cpufreq_policy *policy,
  unsigned int target_freq,
  unsigned int relation)
@@ -521,6 +555,9 @@ static int __init pcc_cpufreq_probe(void)
goto pcch_free;
}

+   max_time_between_cmds = ioread32(_hdr->maximum_time);
+   min_time_between_cmds = ioread32(_hdr->minimum_time);
+
printk(KERN_DEBUG "pcc-cpufreq: (v%s) driver loaded with frequency"
   " limits: %d MHz, %d MHz\n", PCC_VERSION,
   ioread32(_hdr->minimum_frequency),
--
1.8.5.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/