Merge "gunyah: Adding basic initial files needed for vm on Pineapple"

This commit is contained in:
qctecmdr 2022-08-12 19:19:10 -07:00 committed by Gerrit - the friendly Code Review server
commit cf6c961594
10 changed files with 340 additions and 0 deletions

View File

@ -4,6 +4,7 @@ obj-$(CONFIG_KVM) += kvm/
obj-$(CONFIG_XEN) += xen/
obj-$(subst m,y,$(CONFIG_HYPERV)) += hyperv/
obj-$(CONFIG_CRYPTO) += crypto/
obj-$(CONFIG_GUNYAH_DRIVERS) += gunyah/
# for cleaning
subdir- += boot

View File

@ -2186,6 +2186,8 @@ source "drivers/acpi/Kconfig"
source "arch/arm64/kvm/Kconfig"
source "arch/arm64/gunyah/Kconfig"
if CRYPTO
source "arch/arm64/crypto/Kconfig"
endif # CRYPTO

View File

@ -209,6 +209,15 @@ config ARCH_QCOM
help
This enables support for the ARMv8 based Qualcomm chipsets.
config ARCH_QTI_VM
bool "Enable Virtual Machines Support for Qualcomm Technologies, Inc."
depends on ARCH_QCOM
help
This enables support for the Qualcomm Technologies, Inc.'s
Virtual Machines. If you wish to build a kernel that doesn't
require VM support or if you are unsure,
say 'N' here.
config ARCH_PINEAPPLE
bool "Enable support for Qualcomm Technologies, Inc. Pineapple"
depends on ARCH_QCOM

13
arch/arm64/gunyah/Kconfig Normal file
View File

@ -0,0 +1,13 @@
# SPDX-License-Identifier: GPL-2.0-only
menu "Gunyah arm64 drivers"
config GH_ARM64_DRV
tristate "Gunyah arm64 support"
depends on ARM64
help
Gunyah drivers need arch specific support. Add support for
ARM64 features required by Gunyah virtualizaton drivers. All
arm64 specific features like GIC and reset reasons are handled
by drivers under this config.
endmenu

View File

@ -0,0 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_GH_ARM64_DRV) += gh_arm_drv.o
gh_arm_drv-y := gh_arm.o irq.o reset.o

View File

@ -0,0 +1,21 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
*
*/
#include <linux/module.h>
static int __init gh_arm_init(void)
{
return 0;
}
module_init(gh_arm_init);
static void __exit gh_arm_exit(void)
{
}
module_exit(gh_arm_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Qualcomm Technologies, Inc. Gunyah ARM64 Driver");

127
arch/arm64/gunyah/irq.c Normal file
View File

@ -0,0 +1,127 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
*
*/
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/irqdomain.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <linux/gunyah/gh_rm_drv.h>
#define GIC_V3_SPI_MAX 1019
#define GH_RM_NO_IRQ_ALLOC -1
#define IRQ_OFFSET 32
static DEFINE_IDR(gh_rm_free_virq_idr);
/**
* gh_get_irq: Get a Linux IRQ from a Gunyah-compatible vIRQ
* @virq: Gunyah-compatible vIRQ
* @type: IRQ trigger type (IRQ_TYPE_EDGE_RISING)
* @fw_handle: fw node handle
*
* Returns the mapped Linux IRQ# at Gunyah's IRQ domain (i.e. GIC SPI)
*/
int gh_get_irq(u32 virq, u32 type, struct fwnode_handle *fw_handle)
{
struct irq_fwspec fwspec = {};
if (virq < IRQ_OFFSET || virq >= GIC_V3_SPI_MAX) {
pr_warn("%s: expecting an SPI from RM, but got GIC IRQ %d\n",
__func__, virq);
}
fwspec.fwnode = fw_handle;
fwspec.param_count = 3;
fwspec.param[0] = GIC_SPI;
fwspec.param[1] = virq - IRQ_OFFSET;
fwspec.param[2] = type;
return irq_create_fwspec_mapping(&fwspec);
}
EXPORT_SYMBOL(gh_get_irq);
/**
* gh_get_virq: Allocate a new IRQ if RM-VM hasn't already done already
* @base_virq: The base virtual IRQ number.
* @virq: The virtual IRQ number.
*
* Returns Gunyah compatible vIRQ to bind to.
*/
int gh_get_virq(int base_virq, int virq)
{
int ret;
/* Get the next free vIRQ.
* Subtract IRQ_OFFSET from the base virq to get the base SPI.
*
* Assoiate the address of the idr variable itself as a lookup
* ptr. This will help us to free the virq later.
*/
ret = virq = idr_alloc(&gh_rm_free_virq_idr,
&gh_rm_free_virq_idr,
base_virq - IRQ_OFFSET,
GIC_V3_SPI_MAX, GFP_KERNEL);
if (ret < 0)
return ret;
/* Add IRQ_OFFSET offset to make interrupt as hwirq */
virq += IRQ_OFFSET;
return virq;
}
EXPORT_SYMBOL(gh_get_virq);
/**
* gh_put_virq: Deallocates a vIRQ.
* @irq: The IRQ number.
*
* Returns 0 on success and EINVAL if no IRQ was found.
*/
int gh_put_virq(int virq)
{
void *idr_ptr;
int virq_num;
virq_num = virq - IRQ_OFFSET;
/* If the idr_find() returns a valid ptr, it means that the
* virq was allocated by the kernel itself and not by hyp.
* Release the IRQ and free the allocation if that's true.
*/
idr_ptr = idr_find(&gh_rm_free_virq_idr, virq_num);
if (idr_ptr) {
idr_remove(&gh_rm_free_virq_idr, virq_num);
return 0;
}
return -EINVAL;
}
EXPORT_SYMBOL(gh_put_virq);
/**
* gh_put_irq: Deallocate an Linux IRQ.
* @irq: The IRQ number.
*
* Returns 0 on success and EINVAL if no IRQ was found.
*/
int gh_put_irq(int irq)
{
struct irq_data *irq_data;
if (irq <= 0)
return -EINVAL;
irq_data = irq_get_irq_data(irq);
if (!irq_data)
return -EINVAL;
irq_dispose_mapping(irq);
return gh_put_virq(irq_data->hwirq);
}
EXPORT_SYMBOL(gh_put_irq);

51
arch/arm64/gunyah/reset.c Normal file
View File

@ -0,0 +1,51 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
*
*/
#include <linux/gunyah/gh_rm_drv.h>
#include "reset.h"
/**
* gh_arch_validate_vm_exited_notif: Validate the arch specific exit
* reason and provide a generic reason for further use.
* @buff_size: Size of the buffer containing the exit reason
* @hdr_size: Size of the header
* @vm_exited_payload: Struct of exit_reason
*
* If the exit reason is not valid or has an incorrect size, -EINVAL is
* returned, 0 otherwise and also provides a generic reason for exit
* which can be used by drivers.
*/
int gh_arch_validate_vm_exited_notif(size_t buff_size, size_t hdr_size,
struct gh_rm_notif_vm_exited_payload *vm_exited_payload)
{
size_t min_buf_sz = hdr_size | sizeof(*vm_exited_payload);
switch (vm_exited_payload->exit_type) {
case GH_RM_VM_EXIT_TYPE_PSCI_SYSTEM_RESET2:
if ((vm_exited_payload->exit_reason_size !=
MAX_EXIT_REASON_SIZE) ||
(buff_size != min_buf_sz +
sizeof(struct gh_vm_exit_reason_psci_sys_reset2))) {
pr_err("%s: Invalid size for type PSCI_SYSTEM_RESET2: %u\n",
__func__, buff_size - hdr_size);
return -EINVAL;
}
vm_exited_payload->exit_type = GH_RM_VM_EXIT_TYPE_SYSTEM_RESET;
fallthrough;
case GH_RM_VM_EXIT_TYPE_PSCI_SYSTEM_RESET:
vm_exited_payload->exit_type = GH_RM_VM_EXIT_TYPE_SYSTEM_RESET;
break;
case GH_RM_VM_EXIT_TYPE_PSCI_SYSTEM_OFF:
vm_exited_payload->exit_type = GH_RM_VM_EXIT_TYPE_SYSTEM_OFF;
break;
default:
return -EINVAL;
}
return 0;
}
EXPORT_SYMBOL(gh_arch_validate_vm_exited_notif);

48
arch/arm64/gunyah/reset.h Normal file
View File

@ -0,0 +1,48 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
*
*/
#ifndef __RESET_H
#define __RESET_H
#define GH_RM_VM_EXIT_TYPE_PSCI_SYSTEM_OFF 1
#define GH_RM_VM_EXIT_TYPE_PSCI_SYSTEM_RESET 2
#define GH_RM_VM_EXIT_TYPE_PSCI_SYSTEM_RESET2 3
/* GH_RM_VM_EXIT_TYPE_PSCI_SYSTEM_RESET2 */
struct gh_vm_exit_reason_psci_sys_reset2 {
u16 exit_flags;
/* GH_PSCI_SYS_RESET2_EXIT_FLAG_* are bit representations.
* It follows similar flags model as that of VM_EXIT, but
* only if the vendor_reset field in the struct is set
*/
#define GH_PSCI_SYS_RESET2_EXIT_FLAG_TYPE 0x1
#define GH_PSCI_SYS_RESET2_POWEROFF 0 /* Value at bit:0 */
#define GH_PSCI_SYS_RESET2_RESTART 1 /* Value at bit:0 */
#define GH_PSCI_SYS_RESET2_EXIT_FLAG_SYSTEM 0x2
#define GH_PSCI_SYS_RESET2_EXIT_FLAG_WARM 0x4
#define GH_PSCI_SYS_RESET2_EXIT_FLAG_DUMP 0x8
u8 exit_code;
/* Exit codes.
* It follows similar flags model as that of VM_EXIT, but
* only if the vendor_reset field in the struct is set
*/
#define GH_PSCI_SYS_RESET2_CODE_NORMAL 0
#define GH_PSCI_SYS_RESET2_SOFTWARE_ERR 1
#define GH_PSCI_SYS_RESET2_BUS_ERR 2
#define GH_PSCI_SYS_RESET2_DEVICE_ERR 3
u8 reserved:7;
/* If the vendor_reset is set, the above flags and codes apply.
* Else, the entire exit_reason struct is 0, which qualifies as
* PSCI_SYSTEM_WARM_RESET. Hence, first check this field before
* checking others.
*/
u8 vendor_reset:1;
} __packed;
#endif

View File

@ -0,0 +1,64 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
*/
#ifndef __ASM_GH_HCALL_H
#define __ASM_GH_HCALL_H
#include <linux/types.h>
#include <linux/gunyah/hcall_common.h>
/**
* _gh_hcall: Performs an AArch64-specific call into hypervisor using Gunyah ABI
* @hcall_num: Hypercall function ID to invoke
* @args: Hypercall argument registers
* @resp: Pointer to location to store response
*/
static inline int _gh_hcall(const gh_hcall_fnid_t hcall_num,
const struct gh_hcall_args args,
struct gh_hcall_resp *resp)
{
uint64_t _x18;
register uint64_t _x0 asm("x0") = args.arg0;
register uint64_t _x1 asm("x1") = args.arg1;
register uint64_t _x2 asm("x2") = args.arg2;
register uint64_t _x3 asm("x3") = args.arg3;
register uint64_t _x4 asm("x4") = args.arg4;
register uint64_t _x5 asm("x5") = args.arg5;
register uint64_t _x6 asm("x6") = args.arg6;
register uint64_t _x7 asm("x7") = args.arg7;
asm volatile (
#if IS_ENABLED(CONFIG_SHADOW_CALL_STACK)
"str x18, [%[_x18]]\n"
#endif
"hvc %[num]\n"
#if IS_ENABLED(CONFIG_SHADOW_CALL_STACK)
"ldr x18, [%[_x18]]\n"
"str xzr, [%[_x18]]\n"
#endif
: "+r"(_x0), "+r"(_x1), "+r"(_x2), "+r"(_x3), "+r"(_x4),
"+r"(_x5), "+r"(_x6), "+r"(_x7)
: [num] "i" (hcall_num), [_x18] "r"(&_x18)
: "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17",
#if !IS_ENABLED(CONFIG_SHADOW_CALL_STACK)
"x18",
#endif
"memory"
);
resp->resp0 = _x0;
resp->resp1 = _x1;
resp->resp2 = _x2;
resp->resp3 = _x3;
resp->resp4 = _x4;
resp->resp5 = _x5;
resp->resp6 = _x6;
resp->resp7 = _x7;
return _x0;
}
#endif