1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
4 */
5
6 #define pr_fmt(fmt) "gunyah: " fmt
7
8 #include <linux/gunyah.h>
9 #include <linux/module.h>
10 #include <linux/of_platform.h>
11 #include <linux/platform_device.h>
12
13 struct gunyah_info_desc {
14 __le16 id;
15 __le16 owner;
16 __le32 size;
17 __le32 offset;
18 #define INFO_DESC_VALID BIT(31)
19 __le32 flags;
20 };
21
22 static void *info_area;
23
gunyah_get_info(u16 owner,u16 id,size_t * size)24 void *gunyah_get_info(u16 owner, u16 id, size_t *size)
25 {
26 struct gunyah_info_desc *desc = info_area;
27 __le16 le_owner = cpu_to_le16(owner);
28 __le16 le_id = cpu_to_le16(id);
29
30 if (!desc)
31 return ERR_PTR(-ENOENT);
32
33 for (desc = info_area; le32_to_cpu(desc->offset); desc++) {
34 if (!(le32_to_cpu(desc->flags) & INFO_DESC_VALID))
35 continue;
36 mb();
37 if (le_owner == desc->owner && le_id == desc->id) {
38 if (size)
39 *size = le32_to_cpu(desc->size);
40 return info_area + le32_to_cpu(desc->offset);
41 }
42 }
43 return ERR_PTR(-ENOENT);
44 }
45 EXPORT_SYMBOL_GPL(gunyah_get_info);
46
gunyah_init(void)47 static int __init gunyah_init(void)
48 {
49 struct gunyah_hypercall_hyp_identify_resp gunyah_api;
50 unsigned long info_ipa, info_size;
51 enum gunyah_error gh_error;
52
53 if (!arch_is_gunyah_guest())
54 return -ENODEV;
55
56 gunyah_hypercall_hyp_identify(&gunyah_api);
57
58 pr_info("Running under Gunyah hypervisor %llx/v%u\n",
59 FIELD_GET(GUNYAH_API_INFO_VARIANT_MASK, gunyah_api.api_info),
60 gunyah_api_version(&gunyah_api));
61
62 /* Might move this out to individual drivers if there's ever an API version bump */
63 if (gunyah_api_version(&gunyah_api) != GUNYAH_API_V1) {
64 pr_info("Unsupported Gunyah version: %u\n",
65 gunyah_api_version(&gunyah_api));
66 return -ENODEV;
67 }
68
69 gh_error = gunyah_hypercall_addrspace_find_info_area(&info_ipa, &info_size);
70 /* ignore errors for compatability with gh without info_area support */
71 if (gh_error != GUNYAH_ERROR_OK)
72 return 0;
73
74 info_area = memremap(info_ipa, info_size, MEMREMAP_WB);
75 if (!info_area) {
76 pr_err("Failed to map addrspace info area\n");
77 return -ENOMEM;
78 }
79
80 return 0;
81 }
82 core_initcall(gunyah_init);
83
84 MODULE_LICENSE("GPL");
85 MODULE_DESCRIPTION("Gunyah Driver");
86