Skip to content

Commit

Permalink
arm64: FFH: Move ACPI specific code into drivers/acpi/arm64/
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
sudeep-holla authored and ctmarinas committed Jun 13, 2024
1 parent 99e7a8a commit 7a7a1ca
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 105 deletions.
105 changes: 0 additions & 105 deletions arch/arm64/kernel/acpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 change: 1 addition & 0 deletions drivers/acpi/arm64/Makefile
Original file line number Diff line number Diff line change
@@ -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
Expand Down
107 changes: 107 additions & 0 deletions drivers/acpi/arm64/ffh.c
Original file line number Diff line number Diff line change
@@ -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;
}

0 comments on commit 7a7a1ca

Please sign in to comment.