]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.10-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 10 Apr 2014 03:16:08 +0000 (20:16 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 10 Apr 2014 03:16:08 +0000 (20:16 -0700)
added patches:
powernow-k6-correctly-initialize-default-parameters.patch
powernow-k6-disable-cache-when-changing-frequency.patch
powernow-k6-reorder-frequencies.patch

queue-3.10/powernow-k6-correctly-initialize-default-parameters.patch [new file with mode: 0644]
queue-3.10/powernow-k6-disable-cache-when-changing-frequency.patch [new file with mode: 0644]
queue-3.10/powernow-k6-reorder-frequencies.patch [new file with mode: 0644]
queue-3.10/series

diff --git a/queue-3.10/powernow-k6-correctly-initialize-default-parameters.patch b/queue-3.10/powernow-k6-correctly-initialize-default-parameters.patch
new file mode 100644 (file)
index 0000000..fa93fab
--- /dev/null
@@ -0,0 +1,153 @@
+From d82b922a4acc1781d368aceac2f9da43b038cab2 Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+Date: Wed, 11 Dec 2013 19:38:53 -0500
+Subject: powernow-k6: correctly initialize default parameters
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+commit d82b922a4acc1781d368aceac2f9da43b038cab2 upstream.
+
+The powernow-k6 driver used to read the initial multiplier from the
+powernow register. However, there is a problem with this:
+
+* If there was a frequency transition before, the multiplier read from the
+  register corresponds to the current multiplier.
+* If there was no frequency transition since reset, the field in the
+  register always reads as zero, regardless of the current multiplier that
+  is set using switches on the mainboard and that the CPU is running at.
+
+The zero value corresponds to multiplier 4.5, so as a consequence, the
+powernow-k6 driver always assumes multiplier 4.5.
+
+For example, if we have 550MHz CPU with bus frequency 100MHz and
+multiplier 5.5, the powernow-k6 driver thinks that the multiplier is 4.5
+and bus frequency is 122MHz. The powernow-k6 driver then sets the
+multiplier to 4.5, underclocking the CPU to 450MHz, but reports the
+current frequency as 550MHz.
+
+There is no reliable way how to read the initial multiplier. I modified
+the driver so that it contains a table of known frequencies (based on
+parameters of existing CPUs and some common overclocking schemes) and sets
+the multiplier according to the frequency. If the frequency is unknown
+(because of unusual overclocking or underclocking), the user must supply
+the bus speed and maximum multiplier as module parameters.
+
+This patch should be backported to all stable kernels. If it doesn't
+apply cleanly, change it, or ask me to change it.
+
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+
+---
+ drivers/cpufreq/powernow-k6.c |   76 +++++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 72 insertions(+), 4 deletions(-)
+
+--- a/drivers/cpufreq/powernow-k6.c
++++ b/drivers/cpufreq/powernow-k6.c
+@@ -26,6 +26,14 @@
+ static unsigned int                     busfreq;   /* FSB, in 10 kHz */
+ static unsigned int                     max_multiplier;
++static unsigned int                   param_busfreq = 0;
++static unsigned int                   param_max_multiplier = 0;
++
++module_param_named(max_multiplier, param_max_multiplier, uint, S_IRUGO);
++MODULE_PARM_DESC(max_multiplier, "Maximum multiplier (allowed values: 20 30 35 40 45 50 55 60)");
++
++module_param_named(bus_frequency, param_busfreq, uint, S_IRUGO);
++MODULE_PARM_DESC(bus_frequency, "Bus frequency in kHz");
+ /* Clock ratio multiplied by 10 - see table 27 in AMD#23446 */
+ static struct cpufreq_frequency_table clock_ratio[] = {
+@@ -40,6 +48,27 @@ static struct cpufreq_frequency_table cl
+       {0, CPUFREQ_TABLE_END}
+ };
++static const struct {
++      unsigned freq;
++      unsigned mult;
++} usual_frequency_table[] = {
++      { 400000, 40 }, // 100   * 4
++      { 450000, 45 }, // 100   * 4.5
++      { 475000, 50 }, //  95   * 5
++      { 500000, 50 }, // 100   * 5
++      { 506250, 45 }, // 112.5 * 4.5
++      { 533500, 55 }, //  97   * 5.5
++      { 550000, 55 }, // 100   * 5.5
++      { 562500, 50 }, // 112.5 * 5
++      { 570000, 60 }, //  95   * 6
++      { 600000, 60 }, // 100   * 6
++      { 618750, 55 }, // 112.5 * 5.5
++      { 660000, 55 }, // 120   * 5.5
++      { 675000, 60 }, // 112.5 * 6
++      { 720000, 60 }, // 120   * 6
++};
++
++#define FREQ_RANGE            3000
+ /**
+  * powernow_k6_get_cpu_multiplier - returns the current FSB multiplier
+@@ -163,18 +192,57 @@ static int powernow_k6_target(struct cpu
+       return 0;
+ }
+-
+ static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
+ {
+       unsigned int i, f;
+       int result;
++      unsigned khz;
+       if (policy->cpu != 0)
+               return -ENODEV;
+-      /* get frequencies */
+-      max_multiplier = powernow_k6_get_cpu_multiplier();
+-      busfreq = cpu_khz / max_multiplier;
++      max_multiplier = 0;
++      khz = cpu_khz;
++      for (i = 0; i < ARRAY_SIZE(usual_frequency_table); i++) {
++              if (khz >= usual_frequency_table[i].freq - FREQ_RANGE &&
++                  khz <= usual_frequency_table[i].freq + FREQ_RANGE) {
++                      khz = usual_frequency_table[i].freq;
++                      max_multiplier = usual_frequency_table[i].mult;
++                      break;
++              }
++      }
++      if (param_max_multiplier) {
++              for (i = 0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) {
++                      if (clock_ratio[i].index == param_max_multiplier) {
++                              max_multiplier = param_max_multiplier;
++                              goto have_max_multiplier;
++                      }
++              }
++              printk(KERN_ERR "powernow-k6: invalid max_multiplier parameter, valid parameters 20, 30, 35, 40, 45, 50, 55, 60\n");
++              return -EINVAL;
++      }
++
++      if (!max_multiplier) {
++              printk(KERN_WARNING "powernow-k6: unknown frequency %u, cannot determine current multiplier\n", khz);
++              printk(KERN_WARNING "powernow-k6: use module parameters max_multiplier and bus_frequency\n");
++              return -EOPNOTSUPP;
++      }
++
++have_max_multiplier:
++      param_max_multiplier = max_multiplier;
++
++      if (param_busfreq) {
++              if (param_busfreq >= 50000 && param_busfreq <= 150000) {
++                      busfreq = param_busfreq / 10;
++                      goto have_busfreq;
++              }
++              printk(KERN_ERR "powernow-k6: invalid bus_frequency parameter, allowed range 50000 - 150000 kHz\n");
++              return -EINVAL;
++      }
++
++      busfreq = khz / max_multiplier;
++have_busfreq:
++      param_busfreq = busfreq * 10;
+       /* table init */
+       for (i = 0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) {
diff --git a/queue-3.10/powernow-k6-disable-cache-when-changing-frequency.patch b/queue-3.10/powernow-k6-disable-cache-when-changing-frequency.patch
new file mode 100644 (file)
index 0000000..093508c
--- /dev/null
@@ -0,0 +1,144 @@
+From e20e1d0ac02308e2211306fc67abcd0b2668fb8b Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+Date: Wed, 11 Dec 2013 19:38:32 -0500
+Subject: powernow-k6: disable cache when changing frequency
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+commit e20e1d0ac02308e2211306fc67abcd0b2668fb8b upstream.
+
+I found out that a system with k6-3+ processor is unstable during network
+server load. The system locks up or the network card stops receiving. The
+reason for the instability is the CPU frequency scaling.
+
+During frequency transition the processor is in "EPM Stop Grant" state.
+The documentation says that the processor doesn't respond to inquiry
+requests in this state. Consequently, coherency of processor caches and
+bus master devices is not maintained, causing the system instability.
+
+This patch flushes the cache during frequency transition. It fixes the
+instability.
+
+Other minor changes:
+* u64 invalue changed to unsigned long because the variable is 32-bit
+* move the logic to set the multiplier to a separate function
+  powernow_k6_set_cpu_multiplier
+* preserve lower 5 bits of the powernow port instead of 4 (the voltage
+  field has 5 bits)
+* mask interrupts when reading the multiplier, so that the port is not
+  open during other activity (running other kernel code with the port open
+  shouldn't cause any misbehavior, but we should better be safe and keep
+  the port closed)
+
+This patch should be backported to all stable kernels. If it doesn't
+apply cleanly, change it, or ask me to change it.
+
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/cpufreq/powernow-k6.c |   56 +++++++++++++++++++++++++++++-------------
+ 1 file changed, 39 insertions(+), 17 deletions(-)
+
+--- a/drivers/cpufreq/powernow-k6.c
++++ b/drivers/cpufreq/powernow-k6.c
+@@ -44,23 +44,58 @@ static struct cpufreq_frequency_table cl
+ /**
+  * powernow_k6_get_cpu_multiplier - returns the current FSB multiplier
+  *
+- *   Returns the current setting of the frequency multiplier. Core clock
++ * Returns the current setting of the frequency multiplier. Core clock
+  * speed is frequency of the Front-Side Bus multiplied with this value.
+  */
+ static int powernow_k6_get_cpu_multiplier(void)
+ {
+-      u64 invalue = 0;
++      unsigned long invalue = 0;
+       u32 msrval;
++      local_irq_disable();
++
+       msrval = POWERNOW_IOPORT + 0x1;
+       wrmsr(MSR_K6_EPMR, msrval, 0); /* enable the PowerNow port */
+       invalue = inl(POWERNOW_IOPORT + 0x8);
+       msrval = POWERNOW_IOPORT + 0x0;
+       wrmsr(MSR_K6_EPMR, msrval, 0); /* disable it again */
++      local_irq_enable();
++
+       return clock_ratio[(invalue >> 5)&7].index;
+ }
++static void powernow_k6_set_cpu_multiplier(unsigned int best_i)
++{
++      unsigned long outvalue, invalue;
++      unsigned long msrval;
++      unsigned long cr0;
++
++      /* we now need to transform best_i to the BVC format, see AMD#23446 */
++
++      /*
++       * The processor doesn't respond to inquiry cycles while changing the
++       * frequency, so we must disable cache.
++       */
++      local_irq_disable();
++      cr0 = read_cr0();
++      write_cr0(cr0 | X86_CR0_CD);
++      wbinvd();
++
++      outvalue = (1<<12) | (1<<10) | (1<<9) | (best_i<<5);
++
++      msrval = POWERNOW_IOPORT + 0x1;
++      wrmsr(MSR_K6_EPMR, msrval, 0); /* enable the PowerNow port */
++      invalue = inl(POWERNOW_IOPORT + 0x8);
++      invalue = invalue & 0x1f;
++      outvalue = outvalue | invalue;
++      outl(outvalue, (POWERNOW_IOPORT + 0x8));
++      msrval = POWERNOW_IOPORT + 0x0;
++      wrmsr(MSR_K6_EPMR, msrval, 0); /* disable it again */
++
++      write_cr0(cr0);
++      local_irq_enable();
++}
+ /**
+  * powernow_k6_set_state - set the PowerNow! multiplier
+@@ -71,8 +106,6 @@ static int powernow_k6_get_cpu_multiplie
+ static void powernow_k6_set_state(struct cpufreq_policy *policy,
+               unsigned int best_i)
+ {
+-      unsigned long outvalue = 0, invalue = 0;
+-      unsigned long msrval;
+       struct cpufreq_freqs freqs;
+       if (clock_ratio[best_i].index > max_multiplier) {
+@@ -85,18 +118,7 @@ static void powernow_k6_set_state(struct
+       cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
+-      /* we now need to transform best_i to the BVC format, see AMD#23446 */
+-
+-      outvalue = (1<<12) | (1<<10) | (1<<9) | (best_i<<5);
+-
+-      msrval = POWERNOW_IOPORT + 0x1;
+-      wrmsr(MSR_K6_EPMR, msrval, 0); /* enable the PowerNow port */
+-      invalue = inl(POWERNOW_IOPORT + 0x8);
+-      invalue = invalue & 0xf;
+-      outvalue = outvalue | invalue;
+-      outl(outvalue , (POWERNOW_IOPORT + 0x8));
+-      msrval = POWERNOW_IOPORT + 0x0;
+-      wrmsr(MSR_K6_EPMR, msrval, 0); /* disable it again */
++      powernow_k6_set_cpu_multiplier(best_i);
+       cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+@@ -164,7 +186,7 @@ static int powernow_k6_cpu_init(struct c
+       }
+       /* cpuinfo and default policy values */
+-      policy->cpuinfo.transition_latency = 200000;
++      policy->cpuinfo.transition_latency = 500000;
+       policy->cur = busfreq * max_multiplier;
+       result = cpufreq_frequency_table_cpuinfo(policy, clock_ratio);
diff --git a/queue-3.10/powernow-k6-reorder-frequencies.patch b/queue-3.10/powernow-k6-reorder-frequencies.patch
new file mode 100644 (file)
index 0000000..5466a0f
--- /dev/null
@@ -0,0 +1,68 @@
+From 22c73795b101597051924556dce019385a1e2fa0 Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+Date: Wed, 11 Dec 2013 19:39:19 -0500
+Subject: powernow-k6: reorder frequencies
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+commit 22c73795b101597051924556dce019385a1e2fa0 upstream.
+
+This patch reorders reported frequencies from the highest to the lowest,
+just like in other frequency drivers.
+
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+
+---
+ drivers/cpufreq/powernow-k6.c |   17 ++++++++++-------
+ 1 file changed, 10 insertions(+), 7 deletions(-)
+
+--- a/drivers/cpufreq/powernow-k6.c
++++ b/drivers/cpufreq/powernow-k6.c
+@@ -37,17 +37,20 @@ MODULE_PARM_DESC(bus_frequency, "Bus fre
+ /* Clock ratio multiplied by 10 - see table 27 in AMD#23446 */
+ static struct cpufreq_frequency_table clock_ratio[] = {
+-      {45,  /* 000 -> 4.5x */ 0},
++      {60,  /* 110 -> 6.0x */ 0},
++      {55,  /* 011 -> 5.5x */ 0},
+       {50,  /* 001 -> 5.0x */ 0},
++      {45,  /* 000 -> 4.5x */ 0},
+       {40,  /* 010 -> 4.0x */ 0},
+-      {55,  /* 011 -> 5.5x */ 0},
+-      {20,  /* 100 -> 2.0x */ 0},
+-      {30,  /* 101 -> 3.0x */ 0},
+-      {60,  /* 110 -> 6.0x */ 0},
+       {35,  /* 111 -> 3.5x */ 0},
++      {30,  /* 101 -> 3.0x */ 0},
++      {20,  /* 100 -> 2.0x */ 0},
+       {0, CPUFREQ_TABLE_END}
+ };
++static const u8 index_to_register[8] = { 6, 3, 1, 0, 2, 7, 5, 4 };
++static const u8 register_to_index[8] = { 3, 2, 4, 1, 7, 6, 0, 5 };
++
+ static const struct {
+       unsigned freq;
+       unsigned mult;
+@@ -91,7 +94,7 @@ static int powernow_k6_get_cpu_multiplie
+       local_irq_enable();
+-      return clock_ratio[(invalue >> 5)&7].index;
++      return clock_ratio[register_to_index[(invalue >> 5)&7]].index;
+ }
+ static void powernow_k6_set_cpu_multiplier(unsigned int best_i)
+@@ -111,7 +114,7 @@ static void powernow_k6_set_cpu_multipli
+       write_cr0(cr0 | X86_CR0_CD);
+       wbinvd();
+-      outvalue = (1<<12) | (1<<10) | (1<<9) | (best_i<<5);
++      outvalue = (1<<12) | (1<<10) | (1<<9) | (index_to_register[best_i]<<5);
+       msrval = POWERNOW_IOPORT + 0x1;
+       wrmsr(MSR_K6_EPMR, msrval, 0); /* enable the PowerNow port */
index d6cfdf54fe83cbddf3d749bb8b56f9d4cecc3cb9..0dc05c05abc80bbe9110da58368b08b1ae84ffd7 100644 (file)
@@ -1 +1,4 @@
 selinux-correctly-label-proc-inodes-in-use-before-the-policy-is-loaded.patch
+powernow-k6-disable-cache-when-changing-frequency.patch
+powernow-k6-correctly-initialize-default-parameters.patch
+powernow-k6-reorder-frequencies.patch