1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Author: Sudeep Holla <sudeep.holla@arm.com> 4 * Copyright 2021 Arm Limited 5 * 6 * The PCC Address Space also referred as PCC Operation Region pertains to the 7 * region of PCC subspace that succeeds the PCC signature. The PCC Operation 8 * Region works in conjunction with the PCC Table(Platform Communications 9 * Channel Table). PCC subspaces that are marked for use as PCC Operation 10 * Regions must not be used as PCC subspaces for the standard ACPI features 11 * such as CPPC, RASF, PDTT and MPST. These standard features must always use 12 * the PCC Table instead. 13 * 14 * This driver sets up the PCC Address Space and installs an handler to enable 15 * handling of PCC OpRegion in the firmware. 16 * 17 */ 18 #include <linux/kernel.h> 19 #include <linux/acpi.h> 20 #include <linux/completion.h> 21 #include <linux/idr.h> 22 #include <linux/io.h> 23 24 #include <acpi/pcc.h> 25 26 struct pcc_data { 27 struct pcc_mbox_chan *pcc_chan; 28 void __iomem *pcc_comm_addr; 29 struct completion done; 30 struct mbox_client cl; 31 struct acpi_pcc_info ctx; 32 }; 33 34 static struct acpi_pcc_info pcc_ctx; 35 36 static void pcc_rx_callback(struct mbox_client *cl, void *m) 37 { 38 struct pcc_data *data = container_of(cl, struct pcc_data, cl); 39 40 complete(&data->done); 41 } 42 43 static acpi_status 44 acpi_pcc_address_space_setup(acpi_handle region_handle, u32 function, 45 void *handler_context, void **region_context) 46 { 47 struct pcc_data *data; 48 struct acpi_pcc_info *ctx = handler_context; 49 struct pcc_mbox_chan *pcc_chan; 50 51 data = kzalloc(sizeof(*data), GFP_KERNEL); 52 if (!data) 53 return AE_NO_MEMORY; 54 55 data->cl.rx_callback = pcc_rx_callback; 56 data->cl.knows_txdone = true; 57 data->ctx.length = ctx->length; 58 data->ctx.subspace_id = ctx->subspace_id; 59 data->ctx.internal_buffer = ctx->internal_buffer; 60 61 init_completion(&data->done); 62 data->pcc_chan = pcc_mbox_request_channel(&data->cl, ctx->subspace_id); 63 if (IS_ERR(data->pcc_chan)) { 64 pr_err("Failed to find PCC channel for subspace %d\n", 65 ctx->subspace_id); 66 return AE_NOT_FOUND; 67 } 68 69 pcc_chan = data->pcc_chan; 70 data->pcc_comm_addr = acpi_os_ioremap(pcc_chan->shmem_base_addr, 71 pcc_chan->shmem_size); 72 if (!data->pcc_comm_addr) { 73 pr_err("Failed to ioremap PCC comm region mem for %d\n", 74 ctx->subspace_id); 75 return AE_NO_MEMORY; 76 } 77 78 *region_context = data; 79 return AE_OK; 80 } 81 82 static acpi_status 83 acpi_pcc_address_space_handler(u32 function, acpi_physical_address addr, 84 u32 bits, acpi_integer *value, 85 void *handler_context, void *region_context) 86 { 87 int ret; 88 struct pcc_data *data = region_context; 89 90 reinit_completion(&data->done); 91 92 /* Write to Shared Memory */ 93 memcpy_toio(data->pcc_comm_addr, (void *)value, data->ctx.length); 94 95 ret = mbox_send_message(data->pcc_chan->mchan, NULL); 96 if (ret < 0) 97 return AE_ERROR; 98 99 if (data->pcc_chan->mchan->mbox->txdone_irq) 100 wait_for_completion(&data->done); 101 102 mbox_client_txdone(data->pcc_chan->mchan, ret); 103 104 memcpy_fromio(value, data->pcc_comm_addr, data->ctx.length); 105 106 return AE_OK; 107 } 108 109 void __init acpi_init_pcc(void) 110 { 111 acpi_status status; 112 113 status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT, 114 ACPI_ADR_SPACE_PLATFORM_COMM, 115 &acpi_pcc_address_space_handler, 116 &acpi_pcc_address_space_setup, 117 &pcc_ctx); 118 if (ACPI_FAILURE(status)) 119 pr_alert("OperationRegion handler could not be installed\n"); 120 } 121