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 	struct completion done;
35 	struct mbox_client cl;
36 	struct acpi_pcc_info ctx;
37 };
38 
39 static struct acpi_pcc_info pcc_ctx;
40 
41 static 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 
48 static acpi_status
49 acpi_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 	static 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 
87 err_free_channel:
88 	pcc_mbox_free_channel(data->pcc_chan);
89 err_free_data:
90 	kfree(data);
91 
92 	return ret;
93 }
94 
95 static acpi_status
96 acpi_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 
133 void __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 }
145