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 static acpi_status ret; 57 58 data = kzalloc(sizeof(*data), GFP_KERNEL); 59 if (!data) 60 return AE_NO_MEMORY; 61 62 data->cl.rx_callback = pcc_rx_callback; 63 data->cl.knows_txdone = true; 64 data->ctx.length = ctx->length; 65 data->ctx.subspace_id = ctx->subspace_id; 66 data->ctx.internal_buffer = ctx->internal_buffer; 67 68 init_completion(&data->done); 69 data->pcc_chan = pcc_mbox_request_channel(&data->cl, ctx->subspace_id); 70 if (IS_ERR(data->pcc_chan)) { 71 pr_err("Failed to find PCC channel for subspace %d\n", 72 ctx->subspace_id); 73 ret = AE_NOT_FOUND; 74 goto err_free_data; 75 } 76 77 pcc_chan = data->pcc_chan; 78 if (!pcc_chan->mchan->mbox->txdone_irq) { 79 pr_err("This channel-%d does not support interrupt.\n", 80 ctx->subspace_id); 81 ret = AE_SUPPORT; 82 goto err_free_channel; 83 } 84 data->pcc_comm_addr = acpi_os_ioremap(pcc_chan->shmem_base_addr, 85 pcc_chan->shmem_size); 86 if (!data->pcc_comm_addr) { 87 pr_err("Failed to ioremap PCC comm region mem for %d\n", 88 ctx->subspace_id); 89 ret = AE_NO_MEMORY; 90 goto err_free_channel; 91 } 92 93 *region_context = data; 94 return AE_OK; 95 96 err_free_channel: 97 pcc_mbox_free_channel(data->pcc_chan); 98 err_free_data: 99 kfree(data); 100 101 return ret; 102 } 103 104 static acpi_status 105 acpi_pcc_address_space_handler(u32 function, acpi_physical_address addr, 106 u32 bits, acpi_integer *value, 107 void *handler_context, void *region_context) 108 { 109 int ret; 110 struct pcc_data *data = region_context; 111 u64 usecs_lat; 112 113 reinit_completion(&data->done); 114 115 /* Write to Shared Memory */ 116 memcpy_toio(data->pcc_comm_addr, (void *)value, data->ctx.length); 117 118 ret = mbox_send_message(data->pcc_chan->mchan, NULL); 119 if (ret < 0) 120 return AE_ERROR; 121 122 /* 123 * pcc_chan->latency is just a Nominal value. In reality the remote 124 * processor could be much slower to reply. So add an arbitrary 125 * amount of wait on top of Nominal. 126 */ 127 usecs_lat = PCC_CMD_WAIT_RETRIES_NUM * data->pcc_chan->latency; 128 ret = wait_for_completion_timeout(&data->done, 129 usecs_to_jiffies(usecs_lat)); 130 if (ret == 0) { 131 pr_err("PCC command executed timeout!\n"); 132 return AE_TIME; 133 } 134 135 mbox_chan_txdone(data->pcc_chan->mchan, ret); 136 137 memcpy_fromio(value, data->pcc_comm_addr, data->ctx.length); 138 139 return AE_OK; 140 } 141 142 void __init acpi_init_pcc(void) 143 { 144 acpi_status status; 145 146 status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT, 147 ACPI_ADR_SPACE_PLATFORM_COMM, 148 &acpi_pcc_address_space_handler, 149 &acpi_pcc_address_space_setup, 150 &pcc_ctx); 151 if (ACPI_FAILURE(status)) 152 pr_alert("OperationRegion handler could not be installed\n"); 153 } 154