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 /* 27 * Arbitrary retries in case the remote processor is slow to respond 28 * to PCC commands 29 */ 30 #define PCC_CMD_WAIT_RETRIES_NUM 500ULL 31 32 struct pcc_data { 33 struct pcc_mbox_chan *pcc_chan; 34 void __iomem *pcc_comm_addr; 35 struct completion done; 36 struct mbox_client cl; 37 struct acpi_pcc_info ctx; 38 }; 39 40 static struct acpi_pcc_info pcc_ctx; 41 42 static void pcc_rx_callback(struct mbox_client *cl, void *m) 43 { 44 struct pcc_data *data = container_of(cl, struct pcc_data, cl); 45 46 complete(&data->done); 47 } 48 49 static acpi_status 50 acpi_pcc_address_space_setup(acpi_handle region_handle, u32 function, 51 void *handler_context, void **region_context) 52 { 53 struct pcc_data *data; 54 struct acpi_pcc_info *ctx = handler_context; 55 struct pcc_mbox_chan *pcc_chan; 56 57 data = kzalloc(sizeof(*data), GFP_KERNEL); 58 if (!data) 59 return AE_NO_MEMORY; 60 61 data->cl.rx_callback = pcc_rx_callback; 62 data->cl.knows_txdone = true; 63 data->ctx.length = ctx->length; 64 data->ctx.subspace_id = ctx->subspace_id; 65 data->ctx.internal_buffer = ctx->internal_buffer; 66 67 init_completion(&data->done); 68 data->pcc_chan = pcc_mbox_request_channel(&data->cl, ctx->subspace_id); 69 if (IS_ERR(data->pcc_chan)) { 70 pr_err("Failed to find PCC channel for subspace %d\n", 71 ctx->subspace_id); 72 kfree(data); 73 return AE_NOT_FOUND; 74 } 75 76 pcc_chan = data->pcc_chan; 77 data->pcc_comm_addr = acpi_os_ioremap(pcc_chan->shmem_base_addr, 78 pcc_chan->shmem_size); 79 if (!data->pcc_comm_addr) { 80 pr_err("Failed to ioremap PCC comm region mem for %d\n", 81 ctx->subspace_id); 82 pcc_mbox_free_channel(data->pcc_chan); 83 kfree(data); 84 return AE_NO_MEMORY; 85 } 86 87 *region_context = data; 88 return AE_OK; 89 } 90 91 static acpi_status 92 acpi_pcc_address_space_handler(u32 function, acpi_physical_address addr, 93 u32 bits, acpi_integer *value, 94 void *handler_context, void *region_context) 95 { 96 int ret; 97 struct pcc_data *data = region_context; 98 u64 usecs_lat; 99 100 reinit_completion(&data->done); 101 102 /* Write to Shared Memory */ 103 memcpy_toio(data->pcc_comm_addr, (void *)value, data->ctx.length); 104 105 ret = mbox_send_message(data->pcc_chan->mchan, NULL); 106 if (ret < 0) 107 return AE_ERROR; 108 109 if (data->pcc_chan->mchan->mbox->txdone_irq) { 110 /* 111 * pcc_chan->latency is just a Nominal value. In reality the remote 112 * processor could be much slower to reply. So add an arbitrary 113 * amount of wait on top of Nominal. 114 */ 115 usecs_lat = PCC_CMD_WAIT_RETRIES_NUM * data->pcc_chan->latency; 116 ret = wait_for_completion_timeout(&data->done, 117 usecs_to_jiffies(usecs_lat)); 118 if (ret == 0) { 119 pr_err("PCC command executed timeout!\n"); 120 return AE_TIME; 121 } 122 } 123 124 mbox_chan_txdone(data->pcc_chan->mchan, ret); 125 126 memcpy_fromio(value, data->pcc_comm_addr, data->ctx.length); 127 128 return AE_OK; 129 } 130 131 void __init acpi_init_pcc(void) 132 { 133 acpi_status status; 134 135 status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT, 136 ACPI_ADR_SPACE_PLATFORM_COMM, 137 &acpi_pcc_address_space_handler, 138 &acpi_pcc_address_space_setup, 139 &pcc_ctx); 140 if (ACPI_FAILURE(status)) 141 pr_alert("OperationRegion handler could not be installed\n"); 142 } 143