• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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