]> Git Repo - linux.git/blob - drivers/acpi/arm64/ffh.c
drm/v3d: Use v3d_perfmon_find()
[linux.git] / drivers / acpi / arm64 / ffh.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 #include <linux/acpi.h>
3 #include <linux/arm-smccc.h>
4 #include <linux/slab.h>
5
6 /*
7  * Implements ARM64 specific callbacks to support ACPI FFH Operation Region as
8  * specified in https://developer.arm.com/docs/den0048/latest
9  */
10 struct acpi_ffh_data {
11         struct acpi_ffh_info info;
12         void (*invoke_ffh_fn)(unsigned long a0, unsigned long a1,
13                               unsigned long a2, unsigned long a3,
14                               unsigned long a4, unsigned long a5,
15                               unsigned long a6, unsigned long a7,
16                               struct arm_smccc_res *args,
17                               struct arm_smccc_quirk *res);
18         void (*invoke_ffh64_fn)(const struct arm_smccc_1_2_regs *args,
19                                 struct arm_smccc_1_2_regs *res);
20 };
21
22 int acpi_ffh_address_space_arch_setup(void *handler_ctxt, void **region_ctxt)
23 {
24         enum arm_smccc_conduit conduit;
25         struct acpi_ffh_data *ffh_ctxt;
26
27         if (arm_smccc_get_version() < ARM_SMCCC_VERSION_1_2)
28                 return -EOPNOTSUPP;
29
30         conduit = arm_smccc_1_1_get_conduit();
31         if (conduit == SMCCC_CONDUIT_NONE) {
32                 pr_err("%s: invalid SMCCC conduit\n", __func__);
33                 return -EOPNOTSUPP;
34         }
35
36         ffh_ctxt = kzalloc(sizeof(*ffh_ctxt), GFP_KERNEL);
37         if (!ffh_ctxt)
38                 return -ENOMEM;
39
40         if (conduit == SMCCC_CONDUIT_SMC) {
41                 ffh_ctxt->invoke_ffh_fn = __arm_smccc_smc;
42                 ffh_ctxt->invoke_ffh64_fn = arm_smccc_1_2_smc;
43         } else {
44                 ffh_ctxt->invoke_ffh_fn = __arm_smccc_hvc;
45                 ffh_ctxt->invoke_ffh64_fn = arm_smccc_1_2_hvc;
46         }
47
48         memcpy(ffh_ctxt, handler_ctxt, sizeof(ffh_ctxt->info));
49
50         *region_ctxt = ffh_ctxt;
51         return AE_OK;
52 }
53
54 static bool acpi_ffh_smccc_owner_allowed(u32 fid)
55 {
56         int owner = ARM_SMCCC_OWNER_NUM(fid);
57
58         if (owner == ARM_SMCCC_OWNER_STANDARD ||
59             owner == ARM_SMCCC_OWNER_SIP || owner == ARM_SMCCC_OWNER_OEM)
60                 return true;
61
62         return false;
63 }
64
65 int acpi_ffh_address_space_arch_handler(acpi_integer *value, void *region_context)
66 {
67         int ret = 0;
68         struct acpi_ffh_data *ffh_ctxt = region_context;
69
70         if (ffh_ctxt->info.offset == 0) {
71                 /* SMC/HVC 32bit call */
72                 struct arm_smccc_res res;
73                 u32 a[8] = { 0 }, *ptr = (u32 *)value;
74
75                 if (!ARM_SMCCC_IS_FAST_CALL(*ptr) || ARM_SMCCC_IS_64(*ptr) ||
76                     !acpi_ffh_smccc_owner_allowed(*ptr) ||
77                     ffh_ctxt->info.length > 32) {
78                         ret = AE_ERROR;
79                 } else {
80                         int idx, len = ffh_ctxt->info.length >> 2;
81
82                         for (idx = 0; idx < len; idx++)
83                                 a[idx] = *(ptr + idx);
84
85                         ffh_ctxt->invoke_ffh_fn(a[0], a[1], a[2], a[3], a[4],
86                                                 a[5], a[6], a[7], &res, NULL);
87                         memcpy(value, &res, sizeof(res));
88                 }
89
90         } else if (ffh_ctxt->info.offset == 1) {
91                 /* SMC/HVC 64bit call */
92                 struct arm_smccc_1_2_regs *r = (struct arm_smccc_1_2_regs *)value;
93
94                 if (!ARM_SMCCC_IS_FAST_CALL(r->a0) || !ARM_SMCCC_IS_64(r->a0) ||
95                     !acpi_ffh_smccc_owner_allowed(r->a0) ||
96                     ffh_ctxt->info.length > sizeof(*r)) {
97                         ret = AE_ERROR;
98                 } else {
99                         ffh_ctxt->invoke_ffh64_fn(r, r);
100                         memcpy(value, r, ffh_ctxt->info.length);
101                 }
102         } else {
103                 ret = AE_ERROR;
104         }
105
106         return ret;
107 }
This page took 0.038205 seconds and 4 git commands to generate.