Commit f387e5b9 authored by Prakash, Prashanth's avatar Prakash, Prashanth Committed by Rafael J. Wysocki

ACPI / CPPC: use MRTT/MPAR to decide if/when a req can be sent

The ACPI spec defines Minimum Request Turnaround Time(MRTT) and
Maximum Periodic Access Rate(MPAR) to prevent the OSPM from sending
too many requests than the platform can handle. For further details
on these parameters please refer to section 14.1.3 of ACPI 6.0 spec.

This patch includes MRTT/MPAR in deciding if or when a CPPC request
can be sent to the platform to make sure CPPC implementation is
compliant to the spec.
Signed-off-by: default avatarPrashanth Prakash <pprakash@codeaurora.org>
Acked-by: default avatarAshwin Chaugule <ashwin.chaugule@linaro.org>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent beee23ae
...@@ -66,6 +66,7 @@ static u64 comm_base_addr; ...@@ -66,6 +66,7 @@ static u64 comm_base_addr;
static int pcc_subspace_idx = -1; static int pcc_subspace_idx = -1;
static bool pcc_channel_acquired; static bool pcc_channel_acquired;
static ktime_t deadline; static ktime_t deadline;
static unsigned int pcc_mpar, pcc_mrtt;
/* pcc mapped address + header size + offset within PCC subspace */ /* pcc mapped address + header size + offset within PCC subspace */
#define GET_PCC_VADDR(offs) (pcc_comm_addr + 0x8 + (offs)) #define GET_PCC_VADDR(offs) (pcc_comm_addr + 0x8 + (offs))
...@@ -85,6 +86,11 @@ static int check_pcc_chan(void) ...@@ -85,6 +86,11 @@ static int check_pcc_chan(void)
/* Retry in case the remote processor was too slow to catch up. */ /* Retry in case the remote processor was too slow to catch up. */
while (!ktime_after(ktime_get(), next_deadline)) { 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
*/
if (readw_relaxed(&generic_comm_base->status) & PCC_CMD_COMPLETE) { if (readw_relaxed(&generic_comm_base->status) & PCC_CMD_COMPLETE) {
ret = 0; ret = 0;
break; break;
...@@ -104,6 +110,9 @@ static int send_pcc_cmd(u16 cmd) ...@@ -104,6 +110,9 @@ static int send_pcc_cmd(u16 cmd)
int ret = -EIO; int ret = -EIO;
struct acpi_pcct_shared_memory *generic_comm_base = struct acpi_pcct_shared_memory *generic_comm_base =
(struct acpi_pcct_shared_memory *) pcc_comm_addr; (struct acpi_pcct_shared_memory *) pcc_comm_addr;
static ktime_t last_cmd_cmpl_time, last_mpar_reset;
static int mpar_count;
unsigned int time_delta;
/* /*
* For CMD_WRITE we know for a fact the caller should have checked * For CMD_WRITE we know for a fact the caller should have checked
...@@ -115,6 +124,41 @@ static int send_pcc_cmd(u16 cmd) ...@@ -115,6 +124,41 @@ static int send_pcc_cmd(u16 cmd)
return ret; return ret;
} }
/*
* Handle the Minimum Request Turnaround Time(MRTT)
* "The minimum amount of time that OSPM must wait after the completion
* of a command before issuing the next command, in microseconds"
*/
if (pcc_mrtt) {
time_delta = ktime_us_delta(ktime_get(), last_cmd_cmpl_time);
if (pcc_mrtt > time_delta)
udelay(pcc_mrtt - time_delta);
}
/*
* Handle the non-zero Maximum Periodic Access Rate(MPAR)
* "The maximum number of periodic requests that the subspace channel can
* support, reported in commands per minute. 0 indicates no limitation."
*
* This parameter should be ideally zero or large enough so that it can
* handle maximum number of requests that all the cores in the system can
* collectively generate. If it is not, we will follow the spec and just
* not send the request to the platform after hitting the MPAR limit in
* any 60s window
*/
if (pcc_mpar) {
if (mpar_count == 0) {
time_delta = ktime_ms_delta(ktime_get(), last_mpar_reset);
if (time_delta < 60 * MSEC_PER_SEC) {
pr_debug("PCC cmd not sent due to MPAR limit");
return -EIO;
}
last_mpar_reset = ktime_get();
mpar_count = pcc_mpar;
}
mpar_count--;
}
/* Write to the shared comm region. */ /* Write to the shared comm region. */
writew_relaxed(cmd, &generic_comm_base->command); writew_relaxed(cmd, &generic_comm_base->command);
...@@ -135,9 +179,17 @@ static int send_pcc_cmd(u16 cmd) ...@@ -135,9 +179,17 @@ static int send_pcc_cmd(u16 cmd)
* because the actual write()s are done before coming here * because the actual write()s are done before coming here
* and the next READ or WRITE will check if the channel * and the next READ or WRITE will check if the channel
* is busy/free at the entry of this call. * is busy/free at the entry of this call.
*
* If Minimum Request Turnaround Time is non-zero, we need
* to record the completion time of both READ and WRITE
* command for proper handling of MRTT, so we need to check
* for pcc_mrtt in addition to CMD_READ
*/ */
if (cmd == CMD_READ) if (cmd == CMD_READ || pcc_mrtt) {
ret = check_pcc_chan(); ret = check_pcc_chan();
if (pcc_mrtt)
last_cmd_cmpl_time = ktime_get();
}
mbox_client_txdone(pcc_channel, ret); mbox_client_txdone(pcc_channel, ret);
return ret; return ret;
...@@ -375,6 +427,8 @@ static int register_pcc_channel(int pcc_subspace_idx) ...@@ -375,6 +427,8 @@ static int register_pcc_channel(int pcc_subspace_idx)
*/ */
usecs_lat = NUM_RETRIES * cppc_ss->latency; usecs_lat = NUM_RETRIES * cppc_ss->latency;
deadline = ns_to_ktime(usecs_lat * NSEC_PER_USEC); deadline = ns_to_ktime(usecs_lat * NSEC_PER_USEC);
pcc_mrtt = cppc_ss->min_turnaround_time;
pcc_mpar = cppc_ss->max_access_rate;
pcc_comm_addr = acpi_os_ioremap(comm_base_addr, len); pcc_comm_addr = acpi_os_ioremap(comm_base_addr, len);
if (!pcc_comm_addr) { if (!pcc_comm_addr) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment