File Index
Files and directories
Sign in
FILE

acpi_pcc.c

File preview with syntax highlighting.

linux-6.19.14/drivers/acpi/acpi_pcc.c C
  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
 32struct pcc_data {
 33	struct pcc_mbox_chan *pcc_chan;
 34	struct completion done;
 35	struct mbox_client cl;
 36	struct acpi_pcc_info ctx;
 37};
 38
 39static struct acpi_pcc_info pcc_ctx;
 40
 41static void pcc_rx_callback(struct mbox_client *cl, void *m)
 42{
 43	struct pcc_data *data = container_of(cl, struct pcc_data, cl);
 44
 45	complete(&data->done);
 46}
 47
 48static acpi_status
 49acpi_pcc_address_space_setup(acpi_handle region_handle, u32 function,
 50			     void *handler_context,  void **region_context)
 51{
 52	struct pcc_data *data;
 53	struct acpi_pcc_info *ctx = handler_context;
 54	struct pcc_mbox_chan *pcc_chan;
 55	acpi_status ret;
 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		ret = AE_NOT_FOUND;
 73		goto err_free_data;
 74	}
 75
 76	pcc_chan = data->pcc_chan;
 77	if (!pcc_chan->mchan->mbox->txdone_irq) {
 78		pr_err("This channel-%d does not support interrupt.\n",
 79		       ctx->subspace_id);
 80		ret = AE_SUPPORT;
 81		goto err_free_channel;
 82	}
 83
 84	*region_context = data;
 85	return AE_OK;
 86
 87err_free_channel:
 88	pcc_mbox_free_channel(data->pcc_chan);
 89err_free_data:
 90	kfree(data);
 91
 92	return ret;
 93}
 94
 95static acpi_status
 96acpi_pcc_address_space_handler(u32 function, acpi_physical_address addr,
 97			       u32 bits, acpi_integer *value,
 98			       void *handler_context, void *region_context)
 99{
100	int ret;
101	struct pcc_data *data = region_context;
102	u64 usecs_lat;
103
104	reinit_completion(&data->done);
105
106	/* Write to Shared Memory */
107	memcpy_toio(data->pcc_chan->shmem, (void *)value, data->ctx.length);
108
109	ret = mbox_send_message(data->pcc_chan->mchan, NULL);
110	if (ret < 0)
111		return AE_ERROR;
112
113	/*
114	 * pcc_chan->latency is just a Nominal value. In reality the remote
115	 * processor could be much slower to reply. So add an arbitrary
116	 * amount of wait on top of Nominal.
117	 */
118	usecs_lat = PCC_CMD_WAIT_RETRIES_NUM * data->pcc_chan->latency;
119	ret = wait_for_completion_timeout(&data->done,
120						usecs_to_jiffies(usecs_lat));
121	if (ret == 0) {
122		pr_err("PCC command executed timeout!\n");
123		return AE_TIME;
124	}
125
126	mbox_chan_txdone(data->pcc_chan->mchan, ret);
127
128	memcpy_fromio(value, data->pcc_chan->shmem, data->ctx.length);
129
130	return AE_OK;
131}
132
133void __init acpi_init_pcc(void)
134{
135	acpi_status status;
136
137	status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT,
138						    ACPI_ADR_SPACE_PLATFORM_COMM,
139						    &acpi_pcc_address_space_handler,
140						    &acpi_pcc_address_space_setup,
141						    &pcc_ctx);
142	if (ACPI_FAILURE(status))
143		pr_alert("OperationRegion handler could not be installed\n");
144}
~/ Read-only file preview.