@@ -98,22 +98,22 @@ static bool pcc_tx_done(struct mbox_chan *chan)
u16 cmd_delay = pcct_ss->min_turnaround_time;
unsigned int retries = 0;
- /* Try a few times while waiting for platform to consume */
- while (!(readw_relaxed(&generic_comm_base->status)
- & PCC_CMD_COMPLETE)) {
-
- if (retries++ < 5)
- udelay(cmd_delay);
- else {
- /*
- * If the remote is dead, this will cause the Mbox
- * controller to timeout after mbox client.tx_tout
- * msecs.
- */
- pr_err("PCC platform did not respond.\n");
- return false;
- }
- }
+// /* Try a few times while waiting for platform to consume */
+// while (!(readw_relaxed(&generic_comm_base->status)
+// & PCC_CMD_COMPLETE)) {
+//
+// if (retries++ < 5)
+// udelay(cmd_delay);
+// else {
+// /*
+// * If the remote is dead, this will cause the Mbox
+// * controller to timeout after mbox client.tx_tout
+// * msecs.
+// */
+// pr_err("PCC platform did not respond.\n");
+// return false;
+// }
+// }
return true;
}
@@ -127,6 +127,97 @@ static int get_subspace_id(struct mbox_chan *chan)
return id;
}
+#define PCC_HACK
+
+#ifdef PCC_HACK
+
+#include <asm/msr.h>
+
+/* These offsets are from the SSDT9.asl table on the Thinkpad X240 */
+
+/* These are offsets per CPU from which its CPC table begins. */
+int cpu_base[] = {0, 0x64, 0xC8, 0x12C, 0x190, 0x1F4, 0x258, 0x2BC};
+
+/* These are offsets of the registers in each CPC table. */
+#define HIGHEST_PERF_OFFSET 0x0
+#define LOWEST_PERF_OFFSET 0xc
+#define DESIRED_PERF_OFFSET 0x14
+
+static int core_get_min(void)
+{
+ u64 val;
+ rdmsrl(MSR_PLATFORM_INFO, val);
+ return (val >> 40) & 0xff;
+}
+
+static int core_get_max(void)
+{
+ u64 val;
+ rdmsrl(MSR_PLATFORM_INFO, val);
+ return (val >> 8) & 0xff;
+}
+
+static int core_get_turbo(void)
+{
+ u64 value;
+ int nont, ret;
+
+ rdmsrl(MSR_NHM_TURBO_RATIO_LIMIT, value);
+ nont = core_get_max();
+ ret = ((value) & 255);
+ if (ret <= nont)
+ ret = nont;
+ return ret;
+}
+
+static int pcc_send_data(struct mbox_chan *chan, void *data)
+{
+ struct acpi_pcct_subspace *pcct_ss = chan->con_priv;
+ u64 pcc_comm_addr = pcct_ss->base_address;
+ unsigned int cpu;
+ u16 cmd = *(u16 *) data;
+ u64 desired_val;
+
+ /*XXX: Instead of waiting for platform to consume the cmd,
+ * just do what the platform would've done.
+ */
+ switch (cmd) {
+ case 0: //PCC_CMD_READ
+
+ /* XXX: Normally the Platform would need to update all the other CPPC registers as well.
+ * But for this experiment, since we're not really using all of them, we'll only update
+ * what we use.
+ */
+ for_each_possible_cpu(cpu) {
+ *(char*)(pcc_comm_addr + cpu_base[cpu] + HIGHEST_PERF_OFFSET) = core_get_turbo();
+ *(char*)(pcc_comm_addr + cpu_base[cpu] + LOWEST_PERF_OFFSET) = core_get_min();
+ }
+ break;
+ case 1: //PCC_CMD_WRITE
+
+ /* XXX: All this hackery is very X86 Thinkpad X240 specific.
+ * Normally, the cpc_write64() would have all the info on
+ * how, where and what to write.
+ */
+ for_each_possible_cpu(cpu) {
+ desired_val = *(u64*)(pcc_comm_addr + cpu_base[cpu] + DESIRED_PERF_OFFSET);
+
+ if (desired_val) {
+ wrmsrl_on_cpu(cpu, MSR_IA32_PERF_CTL, desired_val << 8);
+ *(u64*)(pcc_comm_addr + cpu_base[cpu] + DESIRED_PERF_OFFSET) = 0;
+ }
+ }
+ break;
+ default:
+ pr_err("Unknown PCC cmd from the OS\n");
+ return 0;
+ }
+
+ return 0;
+}
+
+#else
+
/* Channel lock is already held by mbox controller code. */
static int pcc_send_data(struct mbox_chan *chan, void *data)
{
@@ -171,6 +262,8 @@ out_err:
return ret;
}
+#endif
+
static struct mbox_chan_ops pcc_chan_ops = {
.send_data = pcc_send_data,
.last_tx_done = pcc_tx_done,
Not for upstreaming. Hacked for experiments on the the Thinkpad X240. The pcc_send_data() function is modified to read certain MSRs and update a shared memory region. This enables the PCC client (CPPC in this case) to read from the buffer as though it were getting data from a remote processor. Signed-off-by: Ashwin Chaugule <ashwin.chaugule@linaro.org> --- drivers/mailbox/pcc.c | 125 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 109 insertions(+), 16 deletions(-)