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 #define PCC_SIGNATURE_SIZE sizeof(u32) 32 33 struct pcc_data { 34 struct pcc_mbox_chan *pcc_chan; 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 acpi_pcc_info *ctx = handler_context; 54 struct pcc_mbox_chan *pcc_chan; 55 struct pcc_data *data; 56 acpi_status ret; 57 u64 usecs_lat; 58 59 if (function == ACPI_REGION_DEACTIVATE) { 60 data = *region_context; 61 if (data) { 62 pcc_mbox_free_channel(data->pcc_chan); 63 kfree(data); 64 *region_context = NULL; 65 } 66 return AE_OK; 67 } 68 69 if (function != ACPI_REGION_ACTIVATE) 70 return AE_BAD_PARAMETER; 71 72 data = kzalloc_obj(*data); 73 if (!data) 74 return AE_NO_MEMORY; 75 76 data->cl.rx_callback = pcc_rx_callback; 77 data->cl.knows_txdone = true; 78 data->ctx.length = ctx->length; 79 data->ctx.subspace_id = ctx->subspace_id; 80 data->ctx.internal_buffer = ctx->internal_buffer; 81 82 init_completion(&data->done); 83 data->pcc_chan = pcc_mbox_request_channel(&data->cl, ctx->subspace_id); 84 if (IS_ERR(data->pcc_chan)) { 85 pr_err("Failed to find PCC channel for subspace %d\n", 86 ctx->subspace_id); 87 ret = AE_NOT_FOUND; 88 goto err_free_data; 89 } 90 91 pcc_chan = data->pcc_chan; 92 if (pcc_chan->shmem_size < PCC_SIGNATURE_SIZE || 93 ctx->length > pcc_chan->shmem_size - PCC_SIGNATURE_SIZE) { 94 pr_err("PCC channel-%d shared memory is too small.\n", 95 ctx->subspace_id); 96 ret = AE_AML_REGION_LIMIT; 97 goto err_free_channel; 98 } 99 100 if (!pcc_chan->mchan->mbox->txdone_irq) { 101 pr_err("This channel-%d does not support interrupt.\n", 102 ctx->subspace_id); 103 ret = AE_SUPPORT; 104 goto err_free_channel; 105 } 106 107 /* 108 * pcc_chan->latency is just a Nominal value. In reality the remote 109 * processor could be much slower to reply. So add an arbitrary 110 * amount of wait on top of Nominal. 111 */ 112 usecs_lat = PCC_CMD_WAIT_RETRIES_NUM * pcc_chan->latency; 113 data->cl.tx_tout = DIV_ROUND_UP_ULL(usecs_lat, 1000); 114 if (!data->cl.tx_tout) 115 data->cl.tx_tout = 1; 116 117 *region_context = data; 118 return AE_OK; 119 120 err_free_channel: 121 pcc_mbox_free_channel(data->pcc_chan); 122 err_free_data: 123 kfree(data); 124 125 return ret; 126 } 127 128 static acpi_status 129 acpi_pcc_address_space_handler(u32 function, acpi_physical_address addr, 130 u32 bits, acpi_integer *value, 131 void *handler_context, void *region_context) 132 { 133 struct pcc_data *data = region_context; 134 void __iomem *pcc_opregion; 135 int ret; 136 137 pcc_opregion = data->pcc_chan->shmem + PCC_SIGNATURE_SIZE; 138 139 reinit_completion(&data->done); 140 141 /* Write to the PCC OperationRegion after the shared memory signature. */ 142 memcpy_toio(pcc_opregion, (void *)value, data->ctx.length); 143 144 ret = mbox_send_message(data->pcc_chan->mchan, NULL); 145 if (ret < 0) 146 return AE_ERROR; 147 148 ret = wait_for_completion_timeout(&data->done, 149 msecs_to_jiffies(data->cl.tx_tout)); 150 if (ret == 0) { 151 pr_err("PCC command executed timeout!\n"); 152 return AE_TIME; 153 } 154 155 mbox_chan_txdone(data->pcc_chan->mchan, ret); 156 157 memcpy_fromio(value, pcc_opregion, data->ctx.length); 158 159 return AE_OK; 160 } 161 162 void __init acpi_init_pcc(void) 163 { 164 acpi_status status; 165 166 status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT, 167 ACPI_ADR_SPACE_PLATFORM_COMM, 168 &acpi_pcc_address_space_handler, 169 &acpi_pcc_address_space_setup, 170 &pcc_ctx); 171 if (ACPI_FAILURE(status)) 172 pr_alert("OperationRegion handler could not be installed\n"); 173 } 174