Merge tag 'armsoc-arm64' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
[deliverable/linux.git] / drivers / acpi / cppc_acpi.c
index 6970b44d37d5d8f5d095c7406fe0679e3166b2f6..8adac69dba3da52e5bd4ebb7f0780543fc17c51f 100644 (file)
@@ -66,6 +66,7 @@ static u64 comm_base_addr;
 static int pcc_subspace_idx = -1;
 static bool pcc_channel_acquired;
 static ktime_t deadline;
+static unsigned int pcc_mpar, pcc_mrtt;
 
 /* pcc mapped address + header size + offset within PCC subspace */
 #define GET_PCC_VADDR(offs) (pcc_comm_addr + 0x8 + (offs))
@@ -85,6 +86,11 @@ static int check_pcc_chan(void)
 
        /* 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
+                */
                if (readw_relaxed(&generic_comm_base->status) & PCC_CMD_COMPLETE) {
                        ret = 0;
                        break;
@@ -104,6 +110,9 @@ static int send_pcc_cmd(u16 cmd)
        int ret = -EIO;
        struct acpi_pcct_shared_memory *generic_comm_base =
                (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
@@ -115,11 +124,46 @@ static int send_pcc_cmd(u16 cmd)
                        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. */
-       writew(cmd, &generic_comm_base->command);
+       writew_relaxed(cmd, &generic_comm_base->command);
 
        /* Flip CMD COMPLETE bit */
-       writew(0, &generic_comm_base->status);
+       writew_relaxed(0, &generic_comm_base->status);
 
        /* Ring doorbell */
        ret = mbox_send_message(pcc_channel, &cmd);
@@ -135,9 +179,17 @@ static int send_pcc_cmd(u16 cmd)
         * because the actual write()s are done before coming here
         * and the next READ or WRITE will check if the channel
         * 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();
+               if (pcc_mrtt)
+                       last_cmd_cmpl_time = ktime_get();
+       }
 
        mbox_client_txdone(pcc_channel, ret);
        return ret;
@@ -375,6 +427,8 @@ static int register_pcc_channel(int pcc_subspace_idx)
                 */
                usecs_lat = NUM_RETRIES * cppc_ss->latency;
                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);
                if (!pcc_comm_addr) {
@@ -601,16 +655,16 @@ static int cpc_read(struct cpc_reg *reg, u64 *val)
 
                switch (reg->bit_width) {
                case 8:
-                       *val = readb(vaddr);
+                       *val = readb_relaxed(vaddr);
                        break;
                case 16:
-                       *val = readw(vaddr);
+                       *val = readw_relaxed(vaddr);
                        break;
                case 32:
-                       *val = readl(vaddr);
+                       *val = readl_relaxed(vaddr);
                        break;
                case 64:
-                       *val = readq(vaddr);
+                       *val = readq_relaxed(vaddr);
                        break;
                default:
                        pr_debug("Error: Cannot read %u bit width from PCC\n",
@@ -632,16 +686,16 @@ static int cpc_write(struct cpc_reg *reg, u64 val)
 
                switch (reg->bit_width) {
                case 8:
-                       writeb(val, vaddr);
+                       writeb_relaxed(val, vaddr);
                        break;
                case 16:
-                       writew(val, vaddr);
+                       writew_relaxed(val, vaddr);
                        break;
                case 32:
-                       writel(val, vaddr);
+                       writel_relaxed(val, vaddr);
                        break;
                case 64:
-                       writeq(val, vaddr);
+                       writeq_relaxed(val, vaddr);
                        break;
                default:
                        pr_debug("Error: Cannot write %u bit width to PCC\n",
This page took 0.026873 seconds and 5 git commands to generate.