brintos

brintos / linux-shallow public Read only

0
0
Text · 4.1 KiB · 07a034a Raw
154 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Author: Sudeep Holla <sudeep.holla@arm.com>4 * Copyright 2021 Arm Limited5 *6 * The PCC Address Space also referred as PCC Operation Region pertains to the7 * region of PCC subspace that succeeds the PCC signature. The PCC Operation8 * Region works in conjunction with the PCC Table(Platform Communications9 * Channel Table). PCC subspaces that are marked for use as PCC Operation10 * Regions must not be used as PCC subspaces for the standard ACPI features11 * such as CPPC, RASF, PDTT and MPST. These standard features must always use12 * the PCC Table instead.13 *14 * This driver sets up the PCC Address Space and installs an handler to enable15 * 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 respond28 * to PCC commands29 */30#define PCC_CMD_WAIT_RETRIES_NUM	500ULL31 32struct 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 40static struct acpi_pcc_info pcc_ctx;41 42static 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 49static acpi_status50acpi_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 96err_free_channel:97	pcc_mbox_free_channel(data->pcc_chan);98err_free_data:99	kfree(data);100 101	return ret;102}103 104static acpi_status105acpi_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 remote124	 * processor could be much slower to reply. So add an arbitrary125	 * 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 142void __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