Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Author: Sudeep Holla <sudeep.holla@arm.com>
0004  * Copyright 2021 Arm Limited
0005  *
0006  * The PCC Address Space also referred as PCC Operation Region pertains to the
0007  * region of PCC subspace that succeeds the PCC signature. The PCC Operation
0008  * Region works in conjunction with the PCC Table(Platform Communications
0009  * Channel Table). PCC subspaces that are marked for use as PCC Operation
0010  * Regions must not be used as PCC subspaces for the standard ACPI features
0011  * such as CPPC, RASF, PDTT and MPST. These standard features must always use
0012  * the PCC Table instead.
0013  *
0014  * This driver sets up the PCC Address Space and installs an handler to enable
0015  * handling of PCC OpRegion in the firmware.
0016  *
0017  */
0018 #include <linux/kernel.h>
0019 #include <linux/acpi.h>
0020 #include <linux/completion.h>
0021 #include <linux/idr.h>
0022 #include <linux/io.h>
0023 
0024 #include <acpi/pcc.h>
0025 
0026 struct pcc_data {
0027     struct pcc_mbox_chan *pcc_chan;
0028     void __iomem *pcc_comm_addr;
0029     struct completion done;
0030     struct mbox_client cl;
0031     struct acpi_pcc_info ctx;
0032 };
0033 
0034 static struct acpi_pcc_info pcc_ctx;
0035 
0036 static void pcc_rx_callback(struct mbox_client *cl, void *m)
0037 {
0038     struct pcc_data *data = container_of(cl, struct pcc_data, cl);
0039 
0040     complete(&data->done);
0041 }
0042 
0043 static acpi_status
0044 acpi_pcc_address_space_setup(acpi_handle region_handle, u32 function,
0045                  void *handler_context,  void **region_context)
0046 {
0047     struct pcc_data *data;
0048     struct acpi_pcc_info *ctx = handler_context;
0049     struct pcc_mbox_chan *pcc_chan;
0050 
0051     data = kzalloc(sizeof(*data), GFP_KERNEL);
0052     if (!data)
0053         return AE_NO_MEMORY;
0054 
0055     data->cl.rx_callback = pcc_rx_callback;
0056     data->cl.knows_txdone = true;
0057     data->ctx.length = ctx->length;
0058     data->ctx.subspace_id = ctx->subspace_id;
0059     data->ctx.internal_buffer = ctx->internal_buffer;
0060 
0061     init_completion(&data->done);
0062     data->pcc_chan = pcc_mbox_request_channel(&data->cl, ctx->subspace_id);
0063     if (IS_ERR(data->pcc_chan)) {
0064         pr_err("Failed to find PCC channel for subspace %d\n",
0065                ctx->subspace_id);
0066         return AE_NOT_FOUND;
0067     }
0068 
0069     pcc_chan = data->pcc_chan;
0070     data->pcc_comm_addr = acpi_os_ioremap(pcc_chan->shmem_base_addr,
0071                           pcc_chan->shmem_size);
0072     if (!data->pcc_comm_addr) {
0073         pr_err("Failed to ioremap PCC comm region mem for %d\n",
0074                ctx->subspace_id);
0075         return AE_NO_MEMORY;
0076     }
0077 
0078     *region_context = data;
0079     return AE_OK;
0080 }
0081 
0082 static acpi_status
0083 acpi_pcc_address_space_handler(u32 function, acpi_physical_address addr,
0084                    u32 bits, acpi_integer *value,
0085                    void *handler_context, void *region_context)
0086 {
0087     int ret;
0088     struct pcc_data *data = region_context;
0089 
0090     reinit_completion(&data->done);
0091 
0092     /* Write to Shared Memory */
0093     memcpy_toio(data->pcc_comm_addr, (void *)value, data->ctx.length);
0094 
0095     ret = mbox_send_message(data->pcc_chan->mchan, NULL);
0096     if (ret < 0)
0097         return AE_ERROR;
0098 
0099     if (data->pcc_chan->mchan->mbox->txdone_irq)
0100         wait_for_completion(&data->done);
0101 
0102     mbox_client_txdone(data->pcc_chan->mchan, ret);
0103 
0104     memcpy_fromio(value, data->pcc_comm_addr, data->ctx.length);
0105 
0106     return AE_OK;
0107 }
0108 
0109 void __init acpi_init_pcc(void)
0110 {
0111     acpi_status status;
0112 
0113     status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT,
0114                             ACPI_ADR_SPACE_PLATFORM_COMM,
0115                             &acpi_pcc_address_space_handler,
0116                             &acpi_pcc_address_space_setup,
0117                             &pcc_ctx);
0118     if (ACPI_FAILURE(status))
0119         pr_alert("OperationRegion handler could not be installed\n");
0120 }