xref: /linux/drivers/acpi/acpi_pcc.c (revision 2d7eaeb05ae265bd64270376e6a2c0d80244771f)
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