-
Notifications
You must be signed in to change notification settings - Fork 127
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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>
- Loading branch information
1 parent
99e7a8a
commit 7a7a1ca
Showing
3 changed files
with
108 additions
and
105 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |