diff --git a/drivers/virt/gunyah/gh_rm_drv_private.h b/drivers/virt/gunyah/gh_rm_drv_private.h index e4d0bdedb9cb..5bd94ac69ecc 100644 --- a/drivers/virt/gunyah/gh_rm_drv_private.h +++ b/drivers/virt/gunyah/gh_rm_drv_private.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef __GH_RM_DRV_PRIVATE_H @@ -93,6 +94,11 @@ struct gh_vm_property { /* Message IDs: vRTC Configuration */ #define GH_RM_RPC_MSG_ID_CALL_VM_SET_TIME_BASE 0x56000030 +/* Message IDs: Minidump */ +#define GH_RM_RPC_MSG_ID_CALL_VM_MINIDUMP_GET_INFO 0x56000040 +#define GH_RM_RPC_MSG_ID_CALL_VM_MINIDUMP_REGISTER_RANGE 0x56000041 +#define GH_RM_RPC_MSG_ID_CALL_VM_MINIDUMP_DEREGISTER_SLOT 0x56000042 + /* Message IDs: VM Configuration */ #define GH_RM_RPC_MSG_ID_CALL_VM_IRQ_ACCEPT 0x56000050 #define GH_RM_RPC_MSG_ID_CALL_VM_IRQ_LEND 0x56000051 @@ -444,6 +450,36 @@ struct gh_mem_notify_req_payload { /* End Message ID headers */ +/* Call: MINIDUMP_REGISTER_RANGE */ +struct gh_minidump_get_info_req_payload { + u32 reserved; +} __packed; + +struct gh_minidump_get_info_resp_payload { + u16 slot_num; + u16 reserved; +} __packed; + +struct gh_minidump_register_range_req_hdr { + u64 base_ipa; + u64 region_size; + u32 name_size : 8; + u32 name_offset : 8; + u32 reserved : 16; +} __packed; + +struct gh_minidump_register_range_resp_payload { + u16 slot_num; + u16 reserved; +} __packed; + +struct gh_minidump_deregister_slot_req_payload { + u16 slot_num; + u16 reserved; +} __packed; + +/* End Message ID headers */ + /* Common function declerations */ void gh_init_vm_prop_table(void); int gh_update_vm_prop_table(enum gh_vm_names vm_name, diff --git a/drivers/virt/gunyah/gh_rm_iface.c b/drivers/virt/gunyah/gh_rm_iface.c index ff4fce8e7086..c62772d8c8b5 100644 --- a/drivers/virt/gunyah/gh_rm_iface.c +++ b/drivers/virt/gunyah/gh_rm_iface.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * */ @@ -2281,3 +2282,135 @@ int gh_rm_vm_set_time_base(gh_vmid_t vmid) return 0; } EXPORT_SYMBOL(gh_rm_vm_set_time_base); + +/** + * gh_rm_minidump_get_info: Get available slot number of current VM + * + * On success, the function will return available slot number. + * Otherwise, a negative number will be returned. + */ +int gh_rm_minidump_get_info(void) +{ + struct gh_minidump_get_info_req_payload req_payload = {}; + struct gh_minidump_get_info_resp_payload *resp_payload; + size_t resp_size; + int ret = 0, reply_err_code; + + resp_payload = gh_rm_call(GH_RM_RPC_MSG_ID_CALL_VM_MINIDUMP_GET_INFO, + &req_payload, sizeof(req_payload), &resp_size, + &reply_err_code); + if (reply_err_code || IS_ERR(resp_payload)) { + pr_err("%s failed with err: 0x%llx %d\n", __func__, resp_payload, reply_err_code); + ret = PTR_ERR(resp_payload); + goto err_rm_call; + } + if (resp_size != sizeof(*resp_payload)) { + ret = -EINVAL; + pr_err("%s: Invalid size received: %u\n", __func__, resp_size); + goto err_resp_size; + } + + pr_debug("%s: slot num: %d\n", __func__, resp_payload->slot_num); + ret = resp_payload->slot_num; + +err_resp_size: + kfree(resp_payload); +err_rm_call: + return ret; +} +EXPORT_SYMBOL(gh_rm_minidump_get_info); + +/** + * gh_rm_minidump_register_range: Register a minidump entry + * + * @base_ipa: The base ipa of mem region which need to register + * @region_size: The size of mem region + * @name: The name of minidump entry + * @name_size: The size of entry name + * + * On success, the function will return slot number. Otherwise, a negative number will be + * returned. + */ +int gh_rm_minidump_register_range(phys_addr_t base_ipa, size_t region_size, + const char *name, size_t name_size) +{ + struct gh_minidump_register_range_req_hdr *req_hdr; + struct gh_minidump_register_range_resp_payload *resp_payload; + void *req_buf; + size_t resp_size, req_size; + int ret = 0, reply_err_code; + + if (!name) + return -EINVAL; + req_size = sizeof(*req_hdr); + req_size += name_size; + + req_buf = kmalloc(req_size, GFP_KERNEL); + if (!req_buf) + return -ENOMEM; + + req_hdr = req_buf; + req_hdr->base_ipa = base_ipa; + req_hdr->region_size = region_size; + req_hdr->name_size = name_size; + req_hdr->name_offset = sizeof(*req_hdr) + 8; + memcpy(req_buf + sizeof(*req_hdr), name, name_size); + + resp_payload = + gh_rm_call(GH_RM_RPC_MSG_ID_CALL_VM_MINIDUMP_REGISTER_RANGE, + req_buf, req_size, &resp_size, &reply_err_code); + if (reply_err_code || IS_ERR(resp_payload)) { + pr_err("%s failed with err: 0x%llx %d\n", __func__, resp_payload, reply_err_code); + ret = PTR_ERR(resp_payload); + goto err_rm_call; + } + + if (resp_size != sizeof(*resp_payload)) { + ret = -EINVAL; + pr_err("%s: Invalid size received: %u\n", __func__, resp_size); + goto err_resp_size; + } + ret = resp_payload->slot_num; + + pr_debug("%s: slot num: %d\n", __func__, resp_payload->slot_num); + +err_resp_size: + kfree(resp_payload); +err_rm_call: + kfree(req_buf); + return ret; +} +EXPORT_SYMBOL(gh_rm_minidump_register_range); + +/** + * gh_rm_minidump_deregister_slot: Deregister a minidump entry with slot number + * + * @slot_num: The number of slot which need to be deregistered + * + * On success, the function will return 0. Otherwise, a negative number will be + * returned. + */ +int gh_rm_minidump_deregister_slot(uint16_t slot_num) +{ + struct gh_minidump_deregister_slot_req_payload req_payload = {}; + void *resp; + size_t resp_size; + int reply_err_code; + + req_payload.slot_num = slot_num; + + resp = gh_rm_call(GH_RM_RPC_MSG_ID_CALL_VM_MINIDUMP_DEREGISTER_SLOT, + &req_payload, sizeof(req_payload), &resp_size, + &reply_err_code); + if (reply_err_code || IS_ERR(resp)) { + pr_err("%s failed with err: 0x%llx %d\n", __func__, resp, reply_err_code); + return PTR_ERR(resp); + } + if (resp_size) { + pr_err("%s: Invalid size received: %u\n", __func__, resp_size); + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL(gh_rm_minidump_deregister_slot); diff --git a/include/linux/gunyah/gh_rm_drv.h b/include/linux/gunyah/gh_rm_drv.h index 3fa8683fb62f..6b6906c71137 100644 --- a/include/linux/gunyah/gh_rm_drv.h +++ b/include/linux/gunyah/gh_rm_drv.h @@ -418,6 +418,12 @@ int gh_rm_mem_notify(gh_memparcel_handle_t handle, u8 flags, /* API to set time base */ int gh_rm_vm_set_time_base(gh_vmid_t vmid); +/* API for minidump support */ +int gh_rm_minidump_get_info(void); +int gh_rm_minidump_register_range(phys_addr_t base_ipa, size_t region_size, + const char *name, size_t name_size); +int gh_rm_minidump_deregister_slot(uint16_t slot_num); + #else /* RM client register notifications APIs */ static inline int gh_rm_register_notifier(struct notifier_block *nb) @@ -698,5 +704,24 @@ static inline int gh_rm_vm_set_time_base(gh_vmid_t vmid) { return -EINVAL; } + +/* API for minidump support */ +static inline int gh_rm_minidump_get_info(void) +{ + return -EINVAL; +} + +static inline int gh_rm_minidump_register_range(phys_addr_t base_ipa, + size_t region_size, const char *name, + size_t name_size) +{ + return -EINVAL; +} + +static inline int gh_rm_minidump_deregister_slot(uint16_t slot_num) +{ + return -EINVAL; +} + #endif #endif