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	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_status
50acpi_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_status
105acpi_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
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