Skip to content

Commit 77e2a04

Browse files
sudeep-hollarafaeljw
authored andcommitted
ACPI: PCC: Implement OperationRegion handler for the PCC Type 3 subtype
PCC OpRegion provides a mechanism to communicate with the platform directly from the AML. PCCT provides the list of PCC channel available in the platform, a subset or all of them can be used in PCC Opregion. This patch registers the PCC OpRegion handler before ACPI tables are loaded. This relies on the special context data passed to identify and set up the PCC channel before the OpRegion handler is executed for the first time. Typical PCC Opregion declaration looks like this: OperationRegion (PFRM, PCC, 2, 0x74) Field (PFRM, ByteAcc, NoLock, Preserve) { SIGN, 32, FLGS, 32, LEN, 32, CMD, 32, DATA, 800 } It contains four named double words followed by 100 bytes of buffer names DATA. ASL can fill out the buffer something like: /* Create global or local buffer */ Name (BUFF, Buffer (0x0C){}) /* Create double word fields over the buffer */ CreateDWordField (BUFF, 0x0, WD0) CreateDWordField (BUFF, 0x04, WD1) CreateDWordField (BUFF, 0x08, WD2) /* Fill the named fields */ WD0 = 0x50434300 SIGN = BUFF WD0 = 1 FLGS = BUFF WD0 = 0x10 LEN = BUFF /* Fill the payload in the DATA buffer */ WD0 = 0 WD1 = 0x08 WD2 = 0 DATA = BUFF /* Write to CMD field to trigger handler */ WD0 = 0x4404 CMD = BUFF This buffer is received by acpi_pcc_opregion_space_handler. This handler will fetch the complete buffer via internal_pcc_buffer. The setup handler will receive the special PCC context data which will contain the PCC channel index which used to set up the channel. The buffer pointer and length is saved in region context which is then used in the handler. (kernel test robot: Build failure with CONFIG_ACPI_DEBUGGER) Link: https://lore.kernel.org/r/202201041539.feAV0l27-lkp@intel.com Reported-by: kernel test robot <lkp@intel.com> Signed-off-by: Sudeep Holla <sudeep.holla@arm.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
1 parent c95545a commit 77e2a04

5 files changed

Lines changed: 145 additions & 0 deletions

File tree

drivers/acpi/Kconfig

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,23 @@ config ACPI_PPTT
524524
bool
525525
endif
526526

527+
config ACPI_PCC
528+
bool "ACPI PCC Address Space"
529+
depends on PCC
530+
default y
531+
help
532+
The PCC Address Space also referred as PCC Operation Region pertains
533+
to the region of PCC subspace that succeeds the PCC signature.
534+
535+
The PCC Operation Region works in conjunction with the PCC Table
536+
(Platform Communications Channel Table). PCC subspaces that are
537+
marked for use as PCC Operation Regions must not be used as PCC
538+
subspaces for the standard ACPI features such as CPPC, RASF, PDTT and
539+
MPST. These standard features must always use the PCC Table instead.
540+
541+
Enable this feature if you want to set up and install the PCC Address
542+
Space handler to handle PCC OpRegion in the firmware.
543+
527544
source "drivers/acpi/pmic/Kconfig"
528545

529546
config ACPI_VIOT

drivers/acpi/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ acpi-$(CONFIG_ACPI_LPIT) += acpi_lpit.o
6767
acpi-$(CONFIG_ACPI_GENERIC_GSI) += irq.o
6868
acpi-$(CONFIG_ACPI_WATCHDOG) += acpi_watchdog.o
6969
acpi-$(CONFIG_ACPI_PRMT) += prmt.o
70+
acpi-$(CONFIG_ACPI_PCC) += acpi_pcc.o
7071

7172
# Address translation
7273
acpi-$(CONFIG_ACPI_ADXL) += acpi_adxl.o

drivers/acpi/acpi_pcc.c

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
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+
struct pcc_data {
27+
struct pcc_mbox_chan *pcc_chan;
28+
void __iomem *pcc_comm_addr;
29+
struct completion done;
30+
struct mbox_client cl;
31+
struct acpi_pcc_info ctx;
32+
};
33+
34+
struct acpi_pcc_info pcc_ctx;
35+
36+
static void pcc_rx_callback(struct mbox_client *cl, void *m)
37+
{
38+
struct pcc_data *data = container_of(cl, struct pcc_data, cl);
39+
40+
complete(&data->done);
41+
}
42+
43+
static acpi_status
44+
acpi_pcc_address_space_setup(acpi_handle region_handle, u32 function,
45+
void *handler_context, void **region_context)
46+
{
47+
struct pcc_data *data;
48+
struct acpi_pcc_info *ctx = handler_context;
49+
struct pcc_mbox_chan *pcc_chan;
50+
51+
data = kzalloc(sizeof(*data), GFP_KERNEL);
52+
if (!data)
53+
return AE_NO_MEMORY;
54+
55+
data->cl.rx_callback = pcc_rx_callback;
56+
data->cl.knows_txdone = true;
57+
data->ctx.length = ctx->length;
58+
data->ctx.subspace_id = ctx->subspace_id;
59+
data->ctx.internal_buffer = ctx->internal_buffer;
60+
61+
init_completion(&data->done);
62+
data->pcc_chan = pcc_mbox_request_channel(&data->cl, ctx->subspace_id);
63+
if (IS_ERR(data->pcc_chan)) {
64+
pr_err("Failed to find PCC channel for subspace %d\n",
65+
ctx->subspace_id);
66+
return AE_NOT_FOUND;
67+
}
68+
69+
pcc_chan = data->pcc_chan;
70+
data->pcc_comm_addr = acpi_os_ioremap(pcc_chan->shmem_base_addr,
71+
pcc_chan->shmem_size);
72+
if (!data->pcc_comm_addr) {
73+
pr_err("Failed to ioremap PCC comm region mem for %d\n",
74+
ctx->subspace_id);
75+
return AE_NO_MEMORY;
76+
}
77+
78+
*region_context = data;
79+
return AE_OK;
80+
}
81+
82+
static acpi_status
83+
acpi_pcc_address_space_handler(u32 function, acpi_physical_address addr,
84+
u32 bits, acpi_integer *value,
85+
void *handler_context, void *region_context)
86+
{
87+
int ret;
88+
struct pcc_data *data = region_context;
89+
90+
reinit_completion(&data->done);
91+
92+
/* Write to Shared Memory */
93+
memcpy_toio(data->pcc_comm_addr, (void *)value, data->ctx.length);
94+
95+
ret = mbox_send_message(data->pcc_chan->mchan, NULL);
96+
if (ret < 0)
97+
return AE_ERROR;
98+
99+
if (data->pcc_chan->mchan->mbox->txdone_irq)
100+
wait_for_completion(&data->done);
101+
102+
mbox_client_txdone(data->pcc_chan->mchan, ret);
103+
104+
memcpy_fromio(value, data->pcc_comm_addr, data->ctx.length);
105+
106+
return AE_OK;
107+
}
108+
109+
void __init acpi_init_pcc(void)
110+
{
111+
acpi_status status;
112+
113+
status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT,
114+
ACPI_ADR_SPACE_PLATFORM_COMM,
115+
&acpi_pcc_address_space_handler,
116+
&acpi_pcc_address_space_setup,
117+
&pcc_ctx);
118+
if (ACPI_FAILURE(status))
119+
pr_alert("OperationRegion handler could not be installed\n");
120+
}

drivers/acpi/bus.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1320,6 +1320,7 @@ static int __init acpi_init(void)
13201320
pr_debug("%s: kset create error\n", __func__);
13211321

13221322
init_prmt();
1323+
acpi_init_pcc();
13231324
result = acpi_bus_init();
13241325
if (result) {
13251326
kobject_put(acpi_kobj);

include/linux/acpi.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1389,6 +1389,12 @@ static inline int find_acpi_cpu_cache_topology(unsigned int cpu, int level)
13891389
}
13901390
#endif
13911391

1392+
#ifdef CONFIG_ACPI_PCC
1393+
void acpi_init_pcc(void);
1394+
#else
1395+
static inline void acpi_init_pcc(void) { }
1396+
#endif
1397+
13921398
#ifdef CONFIG_ACPI
13931399
extern void acpi_device_notify(struct device *dev);
13941400
extern void acpi_device_notify_remove(struct device *dev);

0 commit comments

Comments
 (0)