]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ACPI: PCC: Setup PCC Opregion handler only if platform interrupt is available
authorHuisong Li <lihuisong@huawei.com>
Sat, 12 Nov 2022 02:05:27 +0000 (10:05 +0800)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Wed, 23 Nov 2022 18:06:56 +0000 (19:06 +0100)
Currently, PCC OpRegion handler depends on the availability of platform
interrupt to be functional currently. If it is not available, the OpRegion
can't be executed successfully or the desired outcome won't be possible.
So let's reject setting up the PCC OpRegion handler on the platform if
it doesn't support or have platform interrupt available.

Signed-off-by: Huisong Li <lihuisong@huawei.com>
Reviewed-by: Sudeep Holla <sudeep.holla@arm.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
drivers/acpi/acpi_pcc.c

index 3e252be047b852d643269a8a70c4226d92968523..07a034a53acac1e8307265bcc5572054d34d971f 100644 (file)
@@ -53,6 +53,7 @@ acpi_pcc_address_space_setup(acpi_handle region_handle, u32 function,
        struct pcc_data *data;
        struct acpi_pcc_info *ctx = handler_context;
        struct pcc_mbox_chan *pcc_chan;
+       static acpi_status ret;
 
        data = kzalloc(sizeof(*data), GFP_KERNEL);
        if (!data)
@@ -69,23 +70,35 @@ acpi_pcc_address_space_setup(acpi_handle region_handle, u32 function,
        if (IS_ERR(data->pcc_chan)) {
                pr_err("Failed to find PCC channel for subspace %d\n",
                       ctx->subspace_id);
-               kfree(data);
-               return AE_NOT_FOUND;
+               ret = AE_NOT_FOUND;
+               goto err_free_data;
        }
 
        pcc_chan = data->pcc_chan;
+       if (!pcc_chan->mchan->mbox->txdone_irq) {
+               pr_err("This channel-%d does not support interrupt.\n",
+                      ctx->subspace_id);
+               ret = AE_SUPPORT;
+               goto err_free_channel;
+       }
        data->pcc_comm_addr = acpi_os_ioremap(pcc_chan->shmem_base_addr,
                                              pcc_chan->shmem_size);
        if (!data->pcc_comm_addr) {
                pr_err("Failed to ioremap PCC comm region mem for %d\n",
                       ctx->subspace_id);
-               pcc_mbox_free_channel(data->pcc_chan);
-               kfree(data);
-               return AE_NO_MEMORY;
+               ret = AE_NO_MEMORY;
+               goto err_free_channel;
        }
 
        *region_context = data;
        return AE_OK;
+
+err_free_channel:
+       pcc_mbox_free_channel(data->pcc_chan);
+err_free_data:
+       kfree(data);
+
+       return ret;
 }
 
 static acpi_status
@@ -106,19 +119,17 @@ acpi_pcc_address_space_handler(u32 function, acpi_physical_address addr,
        if (ret < 0)
                return AE_ERROR;
 
-       if (data->pcc_chan->mchan->mbox->txdone_irq) {
-               /*
-                * pcc_chan->latency is just a Nominal value. In reality the remote
-                * processor could be much slower to reply. So add an arbitrary
-                * amount of wait on top of Nominal.
-                */
-               usecs_lat = PCC_CMD_WAIT_RETRIES_NUM * data->pcc_chan->latency;
-               ret = wait_for_completion_timeout(&data->done,
-                                                 usecs_to_jiffies(usecs_lat));
-               if (ret == 0) {
-                       pr_err("PCC command executed timeout!\n");
-                       return AE_TIME;
-               }
+       /*
+        * pcc_chan->latency is just a Nominal value. In reality the remote
+        * processor could be much slower to reply. So add an arbitrary
+        * amount of wait on top of Nominal.
+        */
+       usecs_lat = PCC_CMD_WAIT_RETRIES_NUM * data->pcc_chan->latency;
+       ret = wait_for_completion_timeout(&data->done,
+                                               usecs_to_jiffies(usecs_lat));
+       if (ret == 0) {
+               pr_err("PCC command executed timeout!\n");
+               return AE_TIME;
        }
 
        mbox_chan_txdone(data->pcc_chan->mchan, ret);