mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-04 12:12:05 +00:00
arm64: FFH: Move ACPI specific code into drivers/acpi/arm64/
The ACPI FFH Opregion code can be moved out of arm64 arch code as it just uses SMCCC. Move all the ACPI FFH Opregion code into drivers/acpi/arm64/ffh.c Signed-off-by: Sudeep Holla <sudeep.holla@arm.com> Acked-by: Catalin Marinas <catalin.marinas@arm.com> Acked-by: Hanjun Guo <guohanjun@huawei.com> Link: https://lore.kernel.org/r/20240605131458.3341095-4-sudeep.holla@arm.com Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
This commit is contained in:
parent
99e7a8adc0
commit
7a7a1cac3c
@ -422,108 +422,3 @@ void arch_reserve_mem_area(acpi_physical_address addr, size_t size)
|
||||
{
|
||||
memblock_mark_nomap(addr, size);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ACPI_FFH
|
||||
/*
|
||||
* Implements ARM64 specific callbacks to support ACPI FFH Operation Region as
|
||||
* specified in https://developer.arm.com/docs/den0048/latest
|
||||
*/
|
||||
struct acpi_ffh_data {
|
||||
struct acpi_ffh_info info;
|
||||
void (*invoke_ffh_fn)(unsigned long a0, unsigned long a1,
|
||||
unsigned long a2, unsigned long a3,
|
||||
unsigned long a4, unsigned long a5,
|
||||
unsigned long a6, unsigned long a7,
|
||||
struct arm_smccc_res *args,
|
||||
struct arm_smccc_quirk *res);
|
||||
void (*invoke_ffh64_fn)(const struct arm_smccc_1_2_regs *args,
|
||||
struct arm_smccc_1_2_regs *res);
|
||||
};
|
||||
|
||||
int acpi_ffh_address_space_arch_setup(void *handler_ctxt, void **region_ctxt)
|
||||
{
|
||||
enum arm_smccc_conduit conduit;
|
||||
struct acpi_ffh_data *ffh_ctxt;
|
||||
|
||||
if (arm_smccc_get_version() < ARM_SMCCC_VERSION_1_2)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
conduit = arm_smccc_1_1_get_conduit();
|
||||
if (conduit == SMCCC_CONDUIT_NONE) {
|
||||
pr_err("%s: invalid SMCCC conduit\n", __func__);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
ffh_ctxt = kzalloc(sizeof(*ffh_ctxt), GFP_KERNEL);
|
||||
if (!ffh_ctxt)
|
||||
return -ENOMEM;
|
||||
|
||||
if (conduit == SMCCC_CONDUIT_SMC) {
|
||||
ffh_ctxt->invoke_ffh_fn = __arm_smccc_smc;
|
||||
ffh_ctxt->invoke_ffh64_fn = arm_smccc_1_2_smc;
|
||||
} else {
|
||||
ffh_ctxt->invoke_ffh_fn = __arm_smccc_hvc;
|
||||
ffh_ctxt->invoke_ffh64_fn = arm_smccc_1_2_hvc;
|
||||
}
|
||||
|
||||
memcpy(ffh_ctxt, handler_ctxt, sizeof(ffh_ctxt->info));
|
||||
|
||||
*region_ctxt = ffh_ctxt;
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
static bool acpi_ffh_smccc_owner_allowed(u32 fid)
|
||||
{
|
||||
int owner = ARM_SMCCC_OWNER_NUM(fid);
|
||||
|
||||
if (owner == ARM_SMCCC_OWNER_STANDARD ||
|
||||
owner == ARM_SMCCC_OWNER_SIP || owner == ARM_SMCCC_OWNER_OEM)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int acpi_ffh_address_space_arch_handler(acpi_integer *value, void *region_context)
|
||||
{
|
||||
int ret = 0;
|
||||
struct acpi_ffh_data *ffh_ctxt = region_context;
|
||||
|
||||
if (ffh_ctxt->info.offset == 0) {
|
||||
/* SMC/HVC 32bit call */
|
||||
struct arm_smccc_res res;
|
||||
u32 a[8] = { 0 }, *ptr = (u32 *)value;
|
||||
|
||||
if (!ARM_SMCCC_IS_FAST_CALL(*ptr) || ARM_SMCCC_IS_64(*ptr) ||
|
||||
!acpi_ffh_smccc_owner_allowed(*ptr) ||
|
||||
ffh_ctxt->info.length > 32) {
|
||||
ret = AE_ERROR;
|
||||
} else {
|
||||
int idx, len = ffh_ctxt->info.length >> 2;
|
||||
|
||||
for (idx = 0; idx < len; idx++)
|
||||
a[idx] = *(ptr + idx);
|
||||
|
||||
ffh_ctxt->invoke_ffh_fn(a[0], a[1], a[2], a[3], a[4],
|
||||
a[5], a[6], a[7], &res, NULL);
|
||||
memcpy(value, &res, sizeof(res));
|
||||
}
|
||||
|
||||
} else if (ffh_ctxt->info.offset == 1) {
|
||||
/* SMC/HVC 64bit call */
|
||||
struct arm_smccc_1_2_regs *r = (struct arm_smccc_1_2_regs *)value;
|
||||
|
||||
if (!ARM_SMCCC_IS_FAST_CALL(r->a0) || !ARM_SMCCC_IS_64(r->a0) ||
|
||||
!acpi_ffh_smccc_owner_allowed(r->a0) ||
|
||||
ffh_ctxt->info.length > sizeof(*r)) {
|
||||
ret = AE_ERROR;
|
||||
} else {
|
||||
ffh_ctxt->invoke_ffh64_fn(r, r);
|
||||
memcpy(value, r, ffh_ctxt->info.length);
|
||||
}
|
||||
} else {
|
||||
ret = AE_ERROR;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_ACPI_FFH */
|
||||
|
@ -1,6 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
obj-$(CONFIG_ACPI_AGDI) += agdi.o
|
||||
obj-$(CONFIG_ACPI_APMT) += apmt.o
|
||||
obj-$(CONFIG_ACPI_FFH) += ffh.o
|
||||
obj-$(CONFIG_ACPI_GTDT) += gtdt.o
|
||||
obj-$(CONFIG_ACPI_IORT) += iort.o
|
||||
obj-$(CONFIG_ACPI_PROCESSOR_IDLE) += cpuidle.o
|
||||
|
107
drivers/acpi/arm64/ffh.c
Normal file
107
drivers/acpi/arm64/ffh.c
Normal file
@ -0,0 +1,107 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/arm-smccc.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/*
|
||||
* Implements ARM64 specific callbacks to support ACPI FFH Operation Region as
|
||||
* specified in https://developer.arm.com/docs/den0048/latest
|
||||
*/
|
||||
struct acpi_ffh_data {
|
||||
struct acpi_ffh_info info;
|
||||
void (*invoke_ffh_fn)(unsigned long a0, unsigned long a1,
|
||||
unsigned long a2, unsigned long a3,
|
||||
unsigned long a4, unsigned long a5,
|
||||
unsigned long a6, unsigned long a7,
|
||||
struct arm_smccc_res *args,
|
||||
struct arm_smccc_quirk *res);
|
||||
void (*invoke_ffh64_fn)(const struct arm_smccc_1_2_regs *args,
|
||||
struct arm_smccc_1_2_regs *res);
|
||||
};
|
||||
|
||||
int acpi_ffh_address_space_arch_setup(void *handler_ctxt, void **region_ctxt)
|
||||
{
|
||||
enum arm_smccc_conduit conduit;
|
||||
struct acpi_ffh_data *ffh_ctxt;
|
||||
|
||||
if (arm_smccc_get_version() < ARM_SMCCC_VERSION_1_2)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
conduit = arm_smccc_1_1_get_conduit();
|
||||
if (conduit == SMCCC_CONDUIT_NONE) {
|
||||
pr_err("%s: invalid SMCCC conduit\n", __func__);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
ffh_ctxt = kzalloc(sizeof(*ffh_ctxt), GFP_KERNEL);
|
||||
if (!ffh_ctxt)
|
||||
return -ENOMEM;
|
||||
|
||||
if (conduit == SMCCC_CONDUIT_SMC) {
|
||||
ffh_ctxt->invoke_ffh_fn = __arm_smccc_smc;
|
||||
ffh_ctxt->invoke_ffh64_fn = arm_smccc_1_2_smc;
|
||||
} else {
|
||||
ffh_ctxt->invoke_ffh_fn = __arm_smccc_hvc;
|
||||
ffh_ctxt->invoke_ffh64_fn = arm_smccc_1_2_hvc;
|
||||
}
|
||||
|
||||
memcpy(ffh_ctxt, handler_ctxt, sizeof(ffh_ctxt->info));
|
||||
|
||||
*region_ctxt = ffh_ctxt;
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
static bool acpi_ffh_smccc_owner_allowed(u32 fid)
|
||||
{
|
||||
int owner = ARM_SMCCC_OWNER_NUM(fid);
|
||||
|
||||
if (owner == ARM_SMCCC_OWNER_STANDARD ||
|
||||
owner == ARM_SMCCC_OWNER_SIP || owner == ARM_SMCCC_OWNER_OEM)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int acpi_ffh_address_space_arch_handler(acpi_integer *value, void *region_context)
|
||||
{
|
||||
int ret = 0;
|
||||
struct acpi_ffh_data *ffh_ctxt = region_context;
|
||||
|
||||
if (ffh_ctxt->info.offset == 0) {
|
||||
/* SMC/HVC 32bit call */
|
||||
struct arm_smccc_res res;
|
||||
u32 a[8] = { 0 }, *ptr = (u32 *)value;
|
||||
|
||||
if (!ARM_SMCCC_IS_FAST_CALL(*ptr) || ARM_SMCCC_IS_64(*ptr) ||
|
||||
!acpi_ffh_smccc_owner_allowed(*ptr) ||
|
||||
ffh_ctxt->info.length > 32) {
|
||||
ret = AE_ERROR;
|
||||
} else {
|
||||
int idx, len = ffh_ctxt->info.length >> 2;
|
||||
|
||||
for (idx = 0; idx < len; idx++)
|
||||
a[idx] = *(ptr + idx);
|
||||
|
||||
ffh_ctxt->invoke_ffh_fn(a[0], a[1], a[2], a[3], a[4],
|
||||
a[5], a[6], a[7], &res, NULL);
|
||||
memcpy(value, &res, sizeof(res));
|
||||
}
|
||||
|
||||
} else if (ffh_ctxt->info.offset == 1) {
|
||||
/* SMC/HVC 64bit call */
|
||||
struct arm_smccc_1_2_regs *r = (struct arm_smccc_1_2_regs *)value;
|
||||
|
||||
if (!ARM_SMCCC_IS_FAST_CALL(r->a0) || !ARM_SMCCC_IS_64(r->a0) ||
|
||||
!acpi_ffh_smccc_owner_allowed(r->a0) ||
|
||||
ffh_ctxt->info.length > sizeof(*r)) {
|
||||
ret = AE_ERROR;
|
||||
} else {
|
||||
ffh_ctxt->invoke_ffh64_fn(r, r);
|
||||
memcpy(value, r, ffh_ctxt->info.length);
|
||||
}
|
||||
} else {
|
||||
ret = AE_ERROR;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
Loading…
Reference in New Issue
Block a user