[Bionic SRU][Patch 0/8] CPPC: Support for V3 and bug fixes.

classic Classic list List threaded Threaded
10 messages Options
Reply | Threaded
Open this post in threaded view
|

[Bionic SRU][Patch 0/8] CPPC: Support for V3 and bug fixes.

Manoj Iyer
Please consider the following patch set for SRU in Bionic. These patches
address the two bugs:
CPPC additional support: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1796918
CPPC bug fixes: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1796949

The CPPC feature needs to be explicitly enabled in Firmware (default is
disabled) for these patches to be in effect.

I have build a kernel in a PPA and regression tested them on Cavium
Thunder X2 CN99XX system. For test kernel, and detailed test results
please refer to the comments in the bug reports.




--
kernel-team mailing list
[hidden email]
https://lists.ubuntu.com/mailman/listinfo/kernel-team
Reply | Threaded
Open this post in threaded view
|

[PATCH 1/8] ACPI / CPPC: Update all pr_(debug/err) messages to log the susbspace id

Manoj Iyer
From: George Cherian <[hidden email]>

CPPC dirver is aware of multiple PCC subspace IDs. Enhance the debug
and error messages in the driver to print the subspace id. In case of
error it will be helpful to find which particular subspace is failing.

BugLink: http://launchpad.net/bugs/1796949

Signed-off-by: George Cherian <[hidden email]>
Signed-off-by: Rafael J. Wysocki <[hidden email]>
(cherry picked from commit d29abc836843b8c9537b4d778eb2d429a804a5ed)
Signed-off-by: Manoj Iyer <[hidden email]>
---
 drivers/acpi/cppc_acpi.c | 27 ++++++++++++++++-----------
 1 file changed, 16 insertions(+), 11 deletions(-)

diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index 06ea4749ebd9..a4133d73bad5 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -227,7 +227,8 @@ static int check_pcc_chan(int pcc_ss_id, bool chk_err_bit)
  if (likely(!ret))
  pcc_ss_data->platform_owns_pcc = false;
  else
- pr_err("PCC check channel failed. Status=%x\n", status);
+ pr_err("PCC check channel failed for ss: %d. Status=%x\n",
+       pcc_ss_id, status);
 
  return ret;
 }
@@ -291,7 +292,8 @@ static int send_pcc_cmd(int pcc_ss_id, u16 cmd)
  time_delta = ktime_ms_delta(ktime_get(),
     pcc_ss_data->last_mpar_reset);
  if ((time_delta < 60 * MSEC_PER_SEC) && pcc_ss_data->last_mpar_reset) {
- pr_debug("PCC cmd not sent due to MPAR limit");
+ pr_debug("PCC cmd for subspace %d not sent due to MPAR limit",
+ pcc_ss_id);
  ret = -EIO;
  goto end;
  }
@@ -312,8 +314,8 @@ static int send_pcc_cmd(int pcc_ss_id, u16 cmd)
  /* Ring doorbell */
  ret = mbox_send_message(pcc_ss_data->pcc_channel, &cmd);
  if (ret < 0) {
- pr_err("Err sending PCC mbox message. cmd:%d, ret:%d\n",
- cmd, ret);
+ pr_err("Err sending PCC mbox message. ss: %d cmd:%d, ret:%d\n",
+       pcc_ss_id, cmd, ret);
  goto end;
  }
 
@@ -553,7 +555,8 @@ static int register_pcc_channel(int pcc_ss_idx)
  pcc_mbox_request_channel(&cppc_mbox_cl, pcc_ss_idx);
 
  if (IS_ERR(pcc_data[pcc_ss_idx]->pcc_channel)) {
- pr_err("Failed to find PCC communication channel\n");
+ pr_err("Failed to find PCC channel for subspace %d\n",
+       pcc_ss_idx);
  return -ENODEV;
  }
 
@@ -566,7 +569,8 @@ static int register_pcc_channel(int pcc_ss_idx)
  cppc_ss = (pcc_data[pcc_ss_idx]->pcc_channel)->con_priv;
 
  if (!cppc_ss) {
- pr_err("No PCC subspace found for CPPC\n");
+ pr_err("No PCC subspace found for %d CPPC\n",
+       pcc_ss_idx);
  return -ENODEV;
  }
 
@@ -584,7 +588,8 @@ static int register_pcc_channel(int pcc_ss_idx)
  pcc_data[pcc_ss_idx]->pcc_comm_addr =
  acpi_os_ioremap(cppc_ss->base_address, cppc_ss->length);
  if (!pcc_data[pcc_ss_idx]->pcc_comm_addr) {
- pr_err("Failed to ioremap PCC comm region mem\n");
+ pr_err("Failed to ioremap PCC comm region mem for %d\n",
+       pcc_ss_idx);
  return -ENOMEM;
  }
 
@@ -973,8 +978,8 @@ static int cpc_read(int cpu, struct cpc_register_resource *reg_res, u64 *val)
  *val = readq_relaxed(vaddr);
  break;
  default:
- pr_debug("Error: Cannot read %u bit width from PCC\n",
- reg->bit_width);
+ pr_debug("Error: Cannot read %u bit width from PCC for ss: %d\n",
+ reg->bit_width, pcc_ss_id);
  ret_val = -EFAULT;
  }
 
@@ -1012,8 +1017,8 @@ static int cpc_write(int cpu, struct cpc_register_resource *reg_res, u64 val)
  writeq_relaxed(val, vaddr);
  break;
  default:
- pr_debug("Error: Cannot write %u bit width to PCC\n",
- reg->bit_width);
+ pr_debug("Error: Cannot write %u bit width to PCC for ss: %d\n",
+ reg->bit_width, pcc_ss_id);
  ret_val = -EFAULT;
  break;
  }
--
2.17.1


--
kernel-team mailing list
[hidden email]
https://lists.ubuntu.com/mailman/listinfo/kernel-team
Reply | Threaded
Open this post in threaded view
|

[PATCH 2/8] cpufreq: CPPC: Don't set transition_latency

Manoj Iyer
In reply to this post by Manoj Iyer
From: Viresh Kumar <[hidden email]>

Now that the driver has started to set transition_delay_us directly,
there is no need to set transition_latency along with it, as it is not
used by the cpufreq core.

BugLink: http://launchpad.net/bugs/1796949

Signed-off-by: Viresh Kumar <[hidden email]>
Signed-off-by: Rafael J. Wysocki <[hidden email]>
(cherry picked from commit b8b10bc2015cd91350aac68447377c8410a48865)
Signed-off-by: Manoj Iyer <[hidden email]>
---
 drivers/cpufreq/cppc_cpufreq.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
index 8b432d6e846d..bc5fc1630876 100644
--- a/drivers/cpufreq/cppc_cpufreq.c
+++ b/drivers/cpufreq/cppc_cpufreq.c
@@ -162,7 +162,6 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
  cpu->perf_caps.highest_perf;
  policy->cpuinfo.max_freq = cppc_dmi_max_khz;
 
- policy->cpuinfo.transition_latency = cppc_get_transition_latency(cpu_num);
  policy->transition_delay_us = cppc_get_transition_latency(cpu_num) /
  NSEC_PER_USEC;
  policy->shared_type = cpu->shared_type;
--
2.17.1


--
kernel-team mailing list
[hidden email]
https://lists.ubuntu.com/mailman/listinfo/kernel-team
Reply | Threaded
Open this post in threaded view
|

[PATCH 3/8] ACPI / CPPC: Add support for CPPC v3

Manoj Iyer
In reply to this post by Manoj Iyer
From: Prashanth Prakash <[hidden email]>

CPPC V3 introduces two new entries to make it easier to convert between
abstract processor performance and frequency. The two new entries are
lowest frequency and nominal frequency. These are the frequencies
corresponding to lowest and nominal abstract performance.

Add support to read the new entries and populate them as part of the
CPPC performance capabilities which can be used by cpufreq drivers

BugLink: http://launchpad.net/bugs/1796918

Signed-off-by: Prashanth Prakash <[hidden email]>
Signed-off-by: Rafael J. Wysocki <[hidden email]>
(cherry picked from commit 4773e77cdc9b3af93ee1ae7bcf2acf94fde17166)
Signed-off-by: Manoj Iyer <[hidden email]>
---
 drivers/acpi/cppc_acpi.c | 81 ++++++++++++++++++++++++++++++++--------
 include/acpi/cppc_acpi.h | 14 +++++--
 2 files changed, 75 insertions(+), 20 deletions(-)

diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index a4133d73bad5..e9e1be34d817 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -156,6 +156,9 @@ show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, highest_perf);
 show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, lowest_perf);
 show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, nominal_perf);
 show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, lowest_nonlinear_perf);
+show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, lowest_freq);
+show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, nominal_freq);
+
 show_cppc_data(cppc_get_perf_ctrs, cppc_perf_fb_ctrs, reference_perf);
 show_cppc_data(cppc_get_perf_ctrs, cppc_perf_fb_ctrs, wraparound_time);
 
@@ -183,6 +186,8 @@ static struct attribute *cppc_attrs[] = {
  &lowest_perf.attr,
  &lowest_nonlinear_perf.attr,
  &nominal_perf.attr,
+ &nominal_freq.attr,
+ &lowest_freq.attr,
  NULL
 };
 
@@ -613,7 +618,6 @@ bool __weak cpc_ffh_supported(void)
  return false;
 }
 
-
 /**
  * pcc_data_alloc() - Allocate the pcc_data memory for pcc subspace
  *
@@ -641,6 +645,34 @@ int pcc_data_alloc(int pcc_ss_id)
 
  return 0;
 }
+
+/* Check if CPPC revision + num_ent combination is supported */
+static bool is_cppc_supported(int revision, int num_ent)
+{
+ int expected_num_ent;
+
+ switch (revision) {
+ case CPPC_V2_REV:
+ expected_num_ent = CPPC_V2_NUM_ENT;
+ break;
+ case CPPC_V3_REV:
+ expected_num_ent = CPPC_V3_NUM_ENT;
+ break;
+ default:
+ pr_debug("Firmware exports unsupported CPPC revision: %d\n",
+ revision);
+ return false;
+ }
+
+ if (expected_num_ent != num_ent) {
+ pr_debug("Firmware exports %d entries. Expected: %d for CPPC rev:%d\n",
+ num_ent, expected_num_ent, revision);
+ return false;
+ }
+
+ return true;
+}
+
 /*
  * An example CPC table looks like the following.
  *
@@ -731,14 +763,6 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
  cpc_obj->type);
  goto out_free;
  }
-
- /* Only support CPPCv2. Bail otherwise. */
- if (num_ent != CPPC_NUM_ENT) {
- pr_debug("Firmware exports %d entries. Expected: %d\n",
- num_ent, CPPC_NUM_ENT);
- goto out_free;
- }
-
  cpc_ptr->num_entries = num_ent;
 
  /* Second entry should be revision. */
@@ -750,12 +774,10 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
  cpc_obj->type);
  goto out_free;
  }
+ cpc_ptr->version = cpc_rev;
 
- if (cpc_rev != CPPC_REV) {
- pr_debug("Firmware exports revision:%d. Expected:%d\n",
- cpc_rev, CPPC_REV);
+ if (!is_cppc_supported(cpc_rev, num_ent))
  goto out_free;
- }
 
  /* Iterate through remaining entries in _CPC */
  for (i = 2; i < num_ent; i++) {
@@ -808,6 +830,18 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
  }
  }
  per_cpu(cpu_pcc_subspace_idx, pr->id) = pcc_subspace_id;
+
+ /*
+ * Initialize the remaining cpc_regs as unsupported.
+ * Example: In case FW exposes CPPC v2, the below loop will initialize
+ * LOWEST_FREQ and NOMINAL_FREQ regs as unsupported
+ */
+ for (i = num_ent - 2; i < MAX_CPC_REG_ENT; i++) {
+ cpc_ptr->cpc_regs[i].type = ACPI_TYPE_INTEGER;
+ cpc_ptr->cpc_regs[i].cpc_entry.int_value = 0;
+ }
+
+
  /* Store CPU Logical ID */
  cpc_ptr->cpu_id = pr->id;
 
@@ -1037,8 +1071,9 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps)
 {
  struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpunum);
  struct cpc_register_resource *highest_reg, *lowest_reg,
- *lowest_non_linear_reg, *nominal_reg;
- u64 high, low, nom, min_nonlinear;
+ *lowest_non_linear_reg, *nominal_reg,
+ *low_freq_reg = NULL, *nom_freq_reg = NULL;
+ u64 high, low, nom, min_nonlinear, low_f = 0, nom_f = 0;
  int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpunum);
  struct cppc_pcc_data *pcc_ss_data;
  int ret = 0, regs_in_pcc = 0;
@@ -1053,10 +1088,13 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps)
  lowest_reg = &cpc_desc->cpc_regs[LOWEST_PERF];
  lowest_non_linear_reg = &cpc_desc->cpc_regs[LOW_NON_LINEAR_PERF];
  nominal_reg = &cpc_desc->cpc_regs[NOMINAL_PERF];
+ low_freq_reg = &cpc_desc->cpc_regs[LOWEST_FREQ];
+ nom_freq_reg = &cpc_desc->cpc_regs[NOMINAL_FREQ];
 
  /* Are any of the regs PCC ?*/
  if (CPC_IN_PCC(highest_reg) || CPC_IN_PCC(lowest_reg) ||
- CPC_IN_PCC(lowest_non_linear_reg) || CPC_IN_PCC(nominal_reg)) {
+ CPC_IN_PCC(lowest_non_linear_reg) || CPC_IN_PCC(nominal_reg) ||
+ CPC_IN_PCC(low_freq_reg) || CPC_IN_PCC(nom_freq_reg)) {
  regs_in_pcc = 1;
  down_write(&pcc_ss_data->pcc_lock);
  /* Ring doorbell once to update PCC subspace */
@@ -1081,6 +1119,17 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps)
  if (!high || !low || !nom || !min_nonlinear)
  ret = -EFAULT;
 
+ /* Read optional lowest and nominal frequencies if present */
+ if (CPC_SUPPORTED(low_freq_reg))
+ cpc_read(cpunum, low_freq_reg, &low_f);
+
+ if (CPC_SUPPORTED(nom_freq_reg))
+ cpc_read(cpunum, nom_freq_reg, &nom_f);
+
+ perf_caps->lowest_freq = low_f;
+ perf_caps->nominal_freq = nom_f;
+
+
 out_err:
  if (regs_in_pcc)
  up_write(&pcc_ss_data->pcc_lock);
diff --git a/include/acpi/cppc_acpi.h b/include/acpi/cppc_acpi.h
index 2010c0516f27..8e0b8250a139 100644
--- a/include/acpi/cppc_acpi.h
+++ b/include/acpi/cppc_acpi.h
@@ -20,14 +20,16 @@
 #include <acpi/pcc.h>
 #include <acpi/processor.h>
 
-/* Only support CPPCv2 for now. */
-#define CPPC_NUM_ENT 21
-#define CPPC_REV 2
+/* Support CPPCv2 and CPPCv3  */
+#define CPPC_V2_REV 2
+#define CPPC_V3_REV 3
+#define CPPC_V2_NUM_ENT 21
+#define CPPC_V3_NUM_ENT 23
 
 #define PCC_CMD_COMPLETE_MASK (1 << 0)
 #define PCC_ERROR_MASK (1 << 2)
 
-#define MAX_CPC_REG_ENT 19
+#define MAX_CPC_REG_ENT 21
 
 /* CPPC specific PCC commands. */
 #define CMD_READ 0
@@ -91,6 +93,8 @@ enum cppc_regs {
  AUTO_ACT_WINDOW,
  ENERGY_PERF,
  REFERENCE_PERF,
+ LOWEST_FREQ,
+ NOMINAL_FREQ,
 };
 
 /*
@@ -104,6 +108,8 @@ struct cppc_perf_caps {
  u32 nominal_perf;
  u32 lowest_perf;
  u32 lowest_nonlinear_perf;
+ u32 lowest_freq;
+ u32 nominal_freq;
 };
 
 struct cppc_perf_ctrls {
--
2.17.1


--
kernel-team mailing list
[hidden email]
https://lists.ubuntu.com/mailman/listinfo/kernel-team
Reply | Threaded
Open this post in threaded view
|

[PATCH 4/8] ACPI / CPPC: Check for valid PCC subspace only if PCC is used

Manoj Iyer
In reply to this post by Manoj Iyer
From: Prashanth Prakash <[hidden email]>

Changes the behavior where we return error if there are no valid PCC
subspace for a given performance domain.

The ACPI spec does not mandate the use PCC, so it is possible to have
platforms where a PCC subspace may not be present, so we need to check
for a valid PCC subspace ID only if the register is a PCC register.

BugLink: http://launchpad.net/bugs/1796949

Signed-off-by: Prashanth Prakash <[hidden email]>
Signed-off-by: Rafael J. Wysocki <[hidden email]>
(cherry picked from commit 6fa12d584dcba18f67425ce17e9317311a624f81)
Signed-off-by: Manoj Iyer <[hidden email]>
---
 drivers/acpi/cppc_acpi.c | 30 +++++++++++++++++++++---------
 1 file changed, 21 insertions(+), 9 deletions(-)

diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index e9e1be34d817..9dabfff2a573 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -1075,15 +1075,14 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps)
  *low_freq_reg = NULL, *nom_freq_reg = NULL;
  u64 high, low, nom, min_nonlinear, low_f = 0, nom_f = 0;
  int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpunum);
- struct cppc_pcc_data *pcc_ss_data;
+ struct cppc_pcc_data *pcc_ss_data = NULL;
  int ret = 0, regs_in_pcc = 0;
 
- if (!cpc_desc || pcc_ss_id < 0) {
+ if (!cpc_desc) {
  pr_debug("No CPC descriptor for CPU:%d\n", cpunum);
  return -ENODEV;
  }
 
- pcc_ss_data = pcc_data[pcc_ss_id];
  highest_reg = &cpc_desc->cpc_regs[HIGHEST_PERF];
  lowest_reg = &cpc_desc->cpc_regs[LOWEST_PERF];
  lowest_non_linear_reg = &cpc_desc->cpc_regs[LOW_NON_LINEAR_PERF];
@@ -1095,6 +1094,11 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps)
  if (CPC_IN_PCC(highest_reg) || CPC_IN_PCC(lowest_reg) ||
  CPC_IN_PCC(lowest_non_linear_reg) || CPC_IN_PCC(nominal_reg) ||
  CPC_IN_PCC(low_freq_reg) || CPC_IN_PCC(nom_freq_reg)) {
+ if (pcc_ss_id < 0) {
+ pr_debug("Invalid pcc_ss_id\n");
+ return -ENODEV;
+ }
+ pcc_ss_data = pcc_data[pcc_ss_id];
  regs_in_pcc = 1;
  down_write(&pcc_ss_data->pcc_lock);
  /* Ring doorbell once to update PCC subspace */
@@ -1150,16 +1154,15 @@ int cppc_get_perf_ctrs(int cpunum, struct cppc_perf_fb_ctrs *perf_fb_ctrs)
  struct cpc_register_resource *delivered_reg, *reference_reg,
  *ref_perf_reg, *ctr_wrap_reg;
  int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpunum);
- struct cppc_pcc_data *pcc_ss_data;
+ struct cppc_pcc_data *pcc_ss_data = NULL;
  u64 delivered, reference, ref_perf, ctr_wrap_time;
  int ret = 0, regs_in_pcc = 0;
 
- if (!cpc_desc || pcc_ss_id < 0) {
+ if (!cpc_desc) {
  pr_debug("No CPC descriptor for CPU:%d\n", cpunum);
  return -ENODEV;
  }
 
- pcc_ss_data = pcc_data[pcc_ss_id];
  delivered_reg = &cpc_desc->cpc_regs[DELIVERED_CTR];
  reference_reg = &cpc_desc->cpc_regs[REFERENCE_CTR];
  ref_perf_reg = &cpc_desc->cpc_regs[REFERENCE_PERF];
@@ -1175,6 +1178,11 @@ int cppc_get_perf_ctrs(int cpunum, struct cppc_perf_fb_ctrs *perf_fb_ctrs)
  /* Are any of the regs PCC ?*/
  if (CPC_IN_PCC(delivered_reg) || CPC_IN_PCC(reference_reg) ||
  CPC_IN_PCC(ctr_wrap_reg) || CPC_IN_PCC(ref_perf_reg)) {
+ if (pcc_ss_id < 0) {
+ pr_debug("Invalid pcc_ss_id\n");
+ return -ENODEV;
+ }
+ pcc_ss_data = pcc_data[pcc_ss_id];
  down_write(&pcc_ss_data->pcc_lock);
  regs_in_pcc = 1;
  /* Ring doorbell once to update PCC subspace */
@@ -1225,15 +1233,14 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
  struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu);
  struct cpc_register_resource *desired_reg;
  int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu);
- struct cppc_pcc_data *pcc_ss_data;
+ struct cppc_pcc_data *pcc_ss_data = NULL;
  int ret = 0;
 
- if (!cpc_desc || pcc_ss_id < 0) {
+ if (!cpc_desc) {
  pr_debug("No CPC descriptor for CPU:%d\n", cpu);
  return -ENODEV;
  }
 
- pcc_ss_data = pcc_data[pcc_ss_id];
  desired_reg = &cpc_desc->cpc_regs[DESIRED_PERF];
 
  /*
@@ -1244,6 +1251,11 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
  * achieve that goal here
  */
  if (CPC_IN_PCC(desired_reg)) {
+ if (pcc_ss_id < 0) {
+ pr_debug("Invalid pcc_ss_id\n");
+ return -ENODEV;
+ }
+ pcc_ss_data = pcc_data[pcc_ss_id];
  down_read(&pcc_ss_data->pcc_lock); /* BEGIN Phase-I */
  if (pcc_ss_data->platform_owns_pcc) {
  ret = check_pcc_chan(pcc_ss_id, false);
--
2.17.1


--
kernel-team mailing list
[hidden email]
https://lists.ubuntu.com/mailman/listinfo/kernel-team
Reply | Threaded
Open this post in threaded view
|

[PATCH 5/8] cpufreq / CPPC: Support for CPPC v3

Manoj Iyer
In reply to this post by Manoj Iyer
From: Prashanth Prakash <[hidden email]>

Use CPPC v3 entries to convert the abstract processor performance to
processor frequency in KHz.

BugLink: http://launchpad.net/bugs/1796918

Signed-off-by: Prashanth Prakash <[hidden email]>
Acked-by: Viresh Kumar <[hidden email]>
Signed-off-by: Rafael J. Wysocki <[hidden email]>
(cherry picked from commit 256f19d212f260c955a90a0efc7753e11b18e34c)
Signed-off-by: Manoj Iyer <[hidden email]>
---
 drivers/cpufreq/cppc_cpufreq.c | 80 +++++++++++++++++++++++++++++-----
 1 file changed, 68 insertions(+), 12 deletions(-)

diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
index bc5fc1630876..e67e94b0ec14 100644
--- a/drivers/cpufreq/cppc_cpufreq.c
+++ b/drivers/cpufreq/cppc_cpufreq.c
@@ -42,9 +42,6 @@
  */
 static struct cppc_cpudata **all_cpu_data;
 
-/* Capture the max KHz from DMI */
-static u64 cppc_dmi_max_khz;
-
 /* Callback function used to retrieve the max frequency from DMI */
 static void cppc_find_dmi_mhz(const struct dmi_header *dm, void *private)
 {
@@ -75,6 +72,64 @@ static u64 cppc_get_dmi_max_khz(void)
  return (1000 * mhz);
 }
 
+/*
+ * If CPPC lowest_freq and nominal_freq registers are exposed then we can
+ * use them to convert perf to freq and vice versa
+ *
+ * If the perf/freq point lies between Nominal and Lowest, we can treat
+ * (Low perf, Low freq) and (Nom Perf, Nom freq) as 2D co-ordinates of a line
+ * and extrapolate the rest
+ * For perf/freq > Nominal, we use the ratio perf:freq at Nominal for conversion
+ */
+static unsigned int cppc_cpufreq_perf_to_khz(struct cppc_cpudata *cpu,
+ unsigned int perf)
+{
+ static u64 max_khz;
+ struct cppc_perf_caps *caps = &cpu->perf_caps;
+ u64 mul, div;
+
+ if (caps->lowest_freq && caps->nominal_freq) {
+ if (perf >= caps->nominal_perf) {
+ mul = caps->nominal_freq;
+ div = caps->nominal_perf;
+ } else {
+ mul = caps->nominal_freq - caps->lowest_freq;
+ div = caps->nominal_perf - caps->lowest_perf;
+ }
+ } else {
+ if (!max_khz)
+ max_khz = cppc_get_dmi_max_khz();
+ mul = max_khz;
+ div = cpu->perf_caps.highest_perf;
+ }
+ return (u64)perf * mul / div;
+}
+
+static unsigned int cppc_cpufreq_khz_to_perf(struct cppc_cpudata *cpu,
+ unsigned int freq)
+{
+ static u64 max_khz;
+ struct cppc_perf_caps *caps = &cpu->perf_caps;
+ u64  mul, div;
+
+ if (caps->lowest_freq && caps->nominal_freq) {
+ if (freq >= caps->nominal_freq) {
+ mul = caps->nominal_perf;
+ div = caps->nominal_freq;
+ } else {
+ mul = caps->lowest_perf;
+ div = caps->lowest_freq;
+ }
+ } else {
+ if (!max_khz)
+ max_khz = cppc_get_dmi_max_khz();
+ mul = cpu->perf_caps.highest_perf;
+ div = max_khz;
+ }
+
+ return (u64)freq * mul / div;
+}
+
 static int cppc_cpufreq_set_target(struct cpufreq_policy *policy,
  unsigned int target_freq,
  unsigned int relation)
@@ -86,7 +141,7 @@ static int cppc_cpufreq_set_target(struct cpufreq_policy *policy,
 
  cpu = all_cpu_data[policy->cpu];
 
- desired_perf = (u64)target_freq * cpu->perf_caps.highest_perf / cppc_dmi_max_khz;
+ desired_perf = cppc_cpufreq_khz_to_perf(cpu, target_freq);
  /* Return if it is exactly the same perf */
  if (desired_perf == cpu->perf_ctrls.desired_perf)
  return ret;
@@ -143,24 +198,24 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
  return ret;
  }
 
- cppc_dmi_max_khz = cppc_get_dmi_max_khz();
+ /* Convert the lowest and nominal freq from MHz to KHz */
+ cpu->perf_caps.lowest_freq *= 1000;
+ cpu->perf_caps.nominal_freq *= 1000;
 
  /*
  * Set min to lowest nonlinear perf to avoid any efficiency penalty (see
  * Section 8.4.7.1.1.5 of ACPI 6.1 spec)
  */
- policy->min = cpu->perf_caps.lowest_nonlinear_perf * cppc_dmi_max_khz /
- cpu->perf_caps.highest_perf;
- policy->max = cppc_dmi_max_khz;
+ policy->min = cppc_cpufreq_perf_to_khz(cpu, cpu->perf_caps.lowest_nonlinear_perf);
+ policy->max = cppc_cpufreq_perf_to_khz(cpu, cpu->perf_caps.highest_perf);
 
  /*
  * Set cpuinfo.min_freq to Lowest to make the full range of performance
  * available if userspace wants to use any perf between lowest & lowest
  * nonlinear perf
  */
- policy->cpuinfo.min_freq = cpu->perf_caps.lowest_perf * cppc_dmi_max_khz /
- cpu->perf_caps.highest_perf;
- policy->cpuinfo.max_freq = cppc_dmi_max_khz;
+ policy->cpuinfo.min_freq = cppc_cpufreq_perf_to_khz(cpu, cpu->perf_caps.lowest_perf);
+ policy->cpuinfo.max_freq = cppc_cpufreq_perf_to_khz(cpu, cpu->perf_caps.highest_perf);
 
  policy->transition_delay_us = cppc_get_transition_latency(cpu_num) /
  NSEC_PER_USEC;
@@ -187,7 +242,8 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
  cpu->cur_policy = policy;
 
  /* Set policy->cur to max now. The governors will adjust later. */
- policy->cur = cppc_dmi_max_khz;
+ policy->cur = cppc_cpufreq_perf_to_khz(cpu,
+ cpu->perf_caps.highest_perf);
  cpu->perf_ctrls.desired_perf = cpu->perf_caps.highest_perf;
 
  ret = cppc_set_perf(cpu_num, &cpu->perf_ctrls);
--
2.17.1


--
kernel-team mailing list
[hidden email]
https://lists.ubuntu.com/mailman/listinfo/kernel-team
Reply | Threaded
Open this post in threaded view
|

[PATCH 6/8] ACPI / CPPC: Document CPPC sysfs interface

Manoj Iyer
In reply to this post by Manoj Iyer
From: Prashanth Prakash <[hidden email]>

Add a file to describe the CPPC sysfs interface and steps to compute
average delivered performance using the feedback counters.

BugLink: http://launchpad.net/bugs/1796918

Signed-off-by: Prashanth Prakash <[hidden email]>
[ rjw: Minor adjustments ]
Signed-off-by: Rafael J. Wysocki <[hidden email]>
(cherry picked from commit b382bf885269bffaa8444a9310db680f2f0f4151)
Signed-off-by: Manoj Iyer <[hidden email]>
---
 Documentation/acpi/cppc_sysfs.txt | 69 +++++++++++++++++++++++++++++++
 1 file changed, 69 insertions(+)
 create mode 100644 Documentation/acpi/cppc_sysfs.txt

diff --git a/Documentation/acpi/cppc_sysfs.txt b/Documentation/acpi/cppc_sysfs.txt
new file mode 100644
index 000000000000..f20fb445135d
--- /dev/null
+++ b/Documentation/acpi/cppc_sysfs.txt
@@ -0,0 +1,69 @@
+
+ Collaborative Processor Performance Control (CPPC)
+
+CPPC defined in the ACPI spec describes a mechanism for the OS to manage the
+performance of a logical processor on a contigious and abstract performance
+scale. CPPC exposes a set of registers to describe abstract performance scale,
+to request performance levels and to measure per-cpu delivered performance.
+
+For more details on CPPC please refer to the ACPI specification at:
+
+http://uefi.org/specifications
+
+Some of the CPPC registers are exposed via sysfs under:
+
+/sys/devices/system/cpu/cpuX/acpi_cppc/
+
+for each cpu X
+
+--------------------------------------------------------------------------------
+
+$ ls -lR  /sys/devices/system/cpu/cpu0/acpi_cppc/
+/sys/devices/system/cpu/cpu0/acpi_cppc/:
+total 0
+-r--r--r-- 1 root root 65536 Mar  5 19:38 feedback_ctrs
+-r--r--r-- 1 root root 65536 Mar  5 19:38 highest_perf
+-r--r--r-- 1 root root 65536 Mar  5 19:38 lowest_freq
+-r--r--r-- 1 root root 65536 Mar  5 19:38 lowest_nonlinear_perf
+-r--r--r-- 1 root root 65536 Mar  5 19:38 lowest_perf
+-r--r--r-- 1 root root 65536 Mar  5 19:38 nominal_freq
+-r--r--r-- 1 root root 65536 Mar  5 19:38 nominal_perf
+-r--r--r-- 1 root root 65536 Mar  5 19:38 reference_perf
+-r--r--r-- 1 root root 65536 Mar  5 19:38 wraparound_time
+
+--------------------------------------------------------------------------------
+
+* highest_perf : Highest performance of this processor (abstract scale).
+* nominal_perf : Highest sustained performance of this processor (abstract scale).
+* lowest_nonlinear_perf : Lowest performance of this processor with nonlinear
+  power savings (abstract scale).
+* lowest_perf : Lowest performance of this processor (abstract scale).
+
+* lowest_freq : CPU frequency corresponding to lowest_perf (in MHz).
+* nominal_freq : CPU frequency corresponding to nominal_perf (in MHz).
+  The above frequencies should only be used to report processor performance in
+  freqency instead of abstract scale. These values should not be used for any
+  functional decisions.
+
+* feedback_ctrs : Includes both Reference and delivered performance counter.
+  Reference counter ticks up proportional to processor's reference performance.
+  Delivered counter ticks up proportional to processor's delivered performance.
+* wraparound_time: Minimum time for the feedback counters to wraparound (seconds).
+* reference_perf : Performance level at which reference performance counter
+  accumulates (abstract scale).
+
+--------------------------------------------------------------------------------
+
+ Computing Average Delivered Performance
+
+Below describes the steps to compute the average performance delivered by taking
+two different snapshots of feedback counters at time T1 and T2.
+
+T1: Read feedback_ctrs as fbc_t1
+    Wait or run some workload
+T2: Read feedback_ctrs as fbc_t2
+
+delivered_counter_delta = fbc_t2[del] - fbc_t1[del]
+reference_counter_delta = fbc_t2[ref] - fbc_t1[ref]
+
+delivered_perf = (refernce_perf x delivered_counter_delta) / reference_counter_delta
--
2.17.1


--
kernel-team mailing list
[hidden email]
https://lists.ubuntu.com/mailman/listinfo/kernel-team
Reply | Threaded
Open this post in threaded view
|

[PATCH 7/8] ACPI / CPPC: Fix invalid PCC channel status errors

Manoj Iyer
In reply to this post by Manoj Iyer
From: "Prakash, Prashanth" <[hidden email]>

Replace the faulty PCC status register polling code with a iopoll.h
macro to fix incorrect reporting of PCC check errors ("PCC check
channel failed").

There were potential codepaths where we could incorrectly return
PCC channel status as busy even without checking the PCC status
register once or not checking the status register before breaking
out of the polling loop. For example, if the thread polling PCC
status register was preempted and scheduled back after we have
crossed the deadline then we can report that the channel is busy
even without checking the status register.

BugLink: http://launchpad.net/bugs/1796949

Signed-off-by: Prashanth Prakash <[hidden email]>
Signed-off-by: Rafael J. Wysocki <[hidden email]>
(cherry picked from commit 58e1c03536c959e0d45fde8261cb9c15da893fe6)
Signed-off-by: Manoj Iyer <[hidden email]>
---
 drivers/acpi/cppc_acpi.c | 48 ++++++++++++++++------------------------
 1 file changed, 19 insertions(+), 29 deletions(-)

diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index 9dabfff2a573..4ea7a71ed5d7 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -39,6 +39,7 @@
 
 #include <linux/cpufreq.h>
 #include <linux/delay.h>
+#include <linux/iopoll.h>
 #include <linux/ktime.h>
 #include <linux/rwsem.h>
 #include <linux/wait.h>
@@ -49,7 +50,7 @@ struct cppc_pcc_data {
  struct mbox_chan *pcc_channel;
  void __iomem *pcc_comm_addr;
  bool pcc_channel_acquired;
- ktime_t deadline;
+ unsigned int deadline_us;
  unsigned int pcc_mpar, pcc_mrtt, pcc_nominal;
 
  bool pending_pcc_write_cmd; /* Any pending/batched PCC write cmds? */
@@ -198,42 +199,31 @@ static struct kobj_type cppc_ktype = {
 
 static int check_pcc_chan(int pcc_ss_id, bool chk_err_bit)
 {
- int ret = -EIO, status = 0;
+ int ret, status;
  struct cppc_pcc_data *pcc_ss_data = pcc_data[pcc_ss_id];
  struct acpi_pcct_shared_memory __iomem *generic_comm_base =
  pcc_ss_data->pcc_comm_addr;
- ktime_t next_deadline = ktime_add(ktime_get(),
-  pcc_ss_data->deadline);
 
  if (!pcc_ss_data->platform_owns_pcc)
  return 0;
 
- /* Retry in case the remote processor was too slow to catch up. */
- while (!ktime_after(ktime_get(), next_deadline)) {
- /*
- * Per spec, prior to boot the PCC space wil be initialized by
- * platform and should have set the command completion bit when
- * PCC can be used by OSPM
- */
- status = readw_relaxed(&generic_comm_base->status);
- if (status & PCC_CMD_COMPLETE_MASK) {
- ret = 0;
- if (chk_err_bit && (status & PCC_ERROR_MASK))
- ret = -EIO;
- break;
- }
- /*
- * Reducing the bus traffic in case this loop takes longer than
- * a few retries.
- */
- udelay(3);
- }
+ /*
+ * Poll PCC status register every 3us(delay_us) for maximum of
+ * deadline_us(timeout_us) until PCC command complete bit is set(cond)
+ */
+ ret = readw_relaxed_poll_timeout(&generic_comm_base->status, status,
+ status & PCC_CMD_COMPLETE_MASK, 3,
+ pcc_ss_data->deadline_us);
 
- if (likely(!ret))
+ if (likely(!ret)) {
  pcc_ss_data->platform_owns_pcc = false;
- else
- pr_err("PCC check channel failed for ss: %d. Status=%x\n",
-       pcc_ss_id, status);
+ if (chk_err_bit && (status & PCC_ERROR_MASK))
+ ret = -EIO;
+ }
+
+ if (unlikely(ret))
+ pr_err("PCC check channel failed for ss: %d. ret=%d\n",
+       pcc_ss_id, ret);
 
  return ret;
 }
@@ -585,7 +575,7 @@ static int register_pcc_channel(int pcc_ss_idx)
  * So add an arbitrary amount of wait on top of Nominal.
  */
  usecs_lat = NUM_RETRIES * cppc_ss->latency;
- pcc_data[pcc_ss_idx]->deadline = ns_to_ktime(usecs_lat * NSEC_PER_USEC);
+ pcc_data[pcc_ss_idx]->deadline_us = usecs_lat;
  pcc_data[pcc_ss_idx]->pcc_mrtt = cppc_ss->min_turnaround_time;
  pcc_data[pcc_ss_idx]->pcc_mpar = cppc_ss->max_access_rate;
  pcc_data[pcc_ss_idx]->pcc_nominal = cppc_ss->latency;
--
2.17.1


--
kernel-team mailing list
[hidden email]
https://lists.ubuntu.com/mailman/listinfo/kernel-team
Reply | Threaded
Open this post in threaded view
|

[PATCH 8/8] cpufreq / CPPC: Add cpuinfo_cur_freq support for CPPC

Manoj Iyer
In reply to this post by Manoj Iyer
From: George Cherian <[hidden email]>

Per Section 8.4.7.1.3 of ACPI 6.2, the platform provides performance
feedback via set of performance counters. To determine the actual
performance level delivered over time, OSPM may read a set of
performance counters from the Reference Performance Counter Register
and the Delivered Performance Counter Register.

OSPM calculates the delivered performance over a given time period by
taking a beginning and ending snapshot of both the reference and
delivered performance counters, and calculating:

delivered_perf = reference_perf X (delta of delivered_perf counter / delta of reference_perf counter).

Implement the above and hook this up to the cpufreq->get method.

BugLink: http://launchpad.net/bugs/1796918

Signed-off-by: George Cherian <[hidden email]>
Acked-by: Viresh Kumar <[hidden email]>
Acked-by: Prashanth Prakash <[hidden email]>
Signed-off-by: Rafael J. Wysocki <[hidden email]>
(cherry picked from commit 33477d84c26bbfa626da2c032e567a90dd70a528)
Signed-off-by: Manoj Iyer <[hidden email]>
---
 drivers/cpufreq/cppc_cpufreq.c | 52 ++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
index e67e94b0ec14..063bbccb9d70 100644
--- a/drivers/cpufreq/cppc_cpufreq.c
+++ b/drivers/cpufreq/cppc_cpufreq.c
@@ -254,10 +254,62 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
  return ret;
 }
 
+static inline u64 get_delta(u64 t1, u64 t0)
+{
+ if (t1 > t0 || t0 > ~(u32)0)
+ return t1 - t0;
+
+ return (u32)t1 - (u32)t0;
+}
+
+static int cppc_get_rate_from_fbctrs(struct cppc_cpudata *cpu,
+     struct cppc_perf_fb_ctrs fb_ctrs_t0,
+     struct cppc_perf_fb_ctrs fb_ctrs_t1)
+{
+ u64 delta_reference, delta_delivered;
+ u64 reference_perf, delivered_perf;
+
+ reference_perf = fb_ctrs_t0.reference_perf;
+
+ delta_reference = get_delta(fb_ctrs_t1.reference,
+    fb_ctrs_t0.reference);
+ delta_delivered = get_delta(fb_ctrs_t1.delivered,
+    fb_ctrs_t0.delivered);
+
+ /* Check to avoid divide-by zero */
+ if (delta_reference || delta_delivered)
+ delivered_perf = (reference_perf * delta_delivered) /
+ delta_reference;
+ else
+ delivered_perf = cpu->perf_ctrls.desired_perf;
+
+ return cppc_cpufreq_perf_to_khz(cpu, delivered_perf);
+}
+
+static unsigned int cppc_cpufreq_get_rate(unsigned int cpunum)
+{
+ struct cppc_perf_fb_ctrs fb_ctrs_t0 = {0}, fb_ctrs_t1 = {0};
+ struct cppc_cpudata *cpu = all_cpu_data[cpunum];
+ int ret;
+
+ ret = cppc_get_perf_ctrs(cpunum, &fb_ctrs_t0);
+ if (ret)
+ return ret;
+
+ udelay(2); /* 2usec delay between sampling */
+
+ ret = cppc_get_perf_ctrs(cpunum, &fb_ctrs_t1);
+ if (ret)
+ return ret;
+
+ return cppc_get_rate_from_fbctrs(cpu, fb_ctrs_t0, fb_ctrs_t1);
+}
+
 static struct cpufreq_driver cppc_cpufreq_driver = {
  .flags = CPUFREQ_CONST_LOOPS,
  .verify = cppc_verify_policy,
  .target = cppc_cpufreq_set_target,
+ .get = cppc_cpufreq_get_rate,
  .init = cppc_cpufreq_cpu_init,
  .stop_cpu = cppc_cpufreq_stop_cpu,
  .name = "cppc_cpufreq",
--
2.17.1


--
kernel-team mailing list
[hidden email]
https://lists.ubuntu.com/mailman/listinfo/kernel-team
Reply | Threaded
Open this post in threaded view
|

NACK: [Bionic SRU][Patch 0/8] CPPC: Support for V3 and bug fixes.

Stefan Bader-2
In reply to this post by Manoj Iyer
On 11.10.2018 17:47, Manoj Iyer wrote:

> Please consider the following patch set for SRU in Bionic. These patches
> address the two bugs:
> CPPC additional support: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1796918
> CPPC bug fixes: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1796949
>
> The CPPC feature needs to be explicitly enabled in Firmware (default is
> disabled) for these patches to be in effect.
>
> I have build a kernel in a PPA and regression tested them on Cavium
> Thunder X2 CN99XX system. For test kernel, and detailed test results
> please refer to the comments in the bug reports.
>
>
>
>
Additional support sounds like adding feature(s) which should not be mixed with
bug fixes. And one should have good reasons prepared as to why those new
features have to go into a base/released kernel and not into the development kernel.

-Stefan


--
kernel-team mailing list
[hidden email]
https://lists.ubuntu.com/mailman/listinfo/kernel-team

signature.asc (836 bytes) Download Attachment