diff options
| -rw-r--r-- | drivers/hv/mshv_root.h | 10 | ||||
| -rw-r--r-- | drivers/hv/mshv_root_hv_call.c | 95 | ||||
| -rw-r--r-- | drivers/hv/mshv_root_main.c | 22 | ||||
| -rw-r--r-- | include/hyperv/hvgdk_mini.h | 1 | ||||
| -rw-r--r-- | include/hyperv/hvhdk_mini.h | 7 |
5 files changed, 115 insertions, 20 deletions
diff --git a/drivers/hv/mshv_root.h b/drivers/hv/mshv_root.h index 5b57d894358a..3eb815011b46 100644 --- a/drivers/hv/mshv_root.h +++ b/drivers/hv/mshv_root.h @@ -297,11 +297,11 @@ int hv_call_connect_port(u64 port_partition_id, union hv_port_id port_id, int hv_call_disconnect_port(u64 connection_partition_id, union hv_connection_id connection_id); int hv_call_notify_port_ring_empty(u32 sint_index); -int hv_call_map_stat_page(enum hv_stats_object_type type, - const union hv_stats_object_identity *identity, - void **addr); -int hv_call_unmap_stat_page(enum hv_stats_object_type type, - const union hv_stats_object_identity *identity); +int hv_map_stats_page(enum hv_stats_object_type type, + const union hv_stats_object_identity *identity, + void **addr); +int hv_unmap_stats_page(enum hv_stats_object_type type, void *page_addr, + const union hv_stats_object_identity *identity); int hv_call_modify_spa_host_access(u64 partition_id, struct page **pages, u64 page_struct_count, u32 host_access, u32 flags, u8 acquire); diff --git a/drivers/hv/mshv_root_hv_call.c b/drivers/hv/mshv_root_hv_call.c index 6dac9fcc092c..caf02cfa49c9 100644 --- a/drivers/hv/mshv_root_hv_call.c +++ b/drivers/hv/mshv_root_hv_call.c @@ -807,9 +807,51 @@ hv_call_notify_port_ring_empty(u32 sint_index) return hv_result_to_errno(status); } -int hv_call_map_stat_page(enum hv_stats_object_type type, - const union hv_stats_object_identity *identity, - void **addr) +static int hv_call_map_stats_page2(enum hv_stats_object_type type, + const union hv_stats_object_identity *identity, + u64 map_location) +{ + unsigned long flags; + struct hv_input_map_stats_page2 *input; + u64 status; + int ret; + + if (!map_location || !mshv_use_overlay_gpfn()) + return -EINVAL; + + do { + local_irq_save(flags); + input = *this_cpu_ptr(hyperv_pcpu_input_arg); + + memset(input, 0, sizeof(*input)); + input->type = type; + input->identity = *identity; + input->map_location = map_location; + + status = hv_do_hypercall(HVCALL_MAP_STATS_PAGE2, input, NULL); + + local_irq_restore(flags); + + ret = hv_result_to_errno(status); + + if (!ret) + break; + + if (hv_result(status) != HV_STATUS_INSUFFICIENT_MEMORY) { + hv_status_debug(status, "\n"); + break; + } + + ret = hv_call_deposit_pages(NUMA_NO_NODE, + hv_current_partition_id, 1); + } while (!ret); + + return ret; +} + +static int hv_call_map_stats_page(enum hv_stats_object_type type, + const union hv_stats_object_identity *identity, + void **addr) { unsigned long flags; struct hv_input_map_stats_page *input; @@ -848,8 +890,38 @@ int hv_call_map_stat_page(enum hv_stats_object_type type, return ret; } -int hv_call_unmap_stat_page(enum hv_stats_object_type type, - const union hv_stats_object_identity *identity) +int hv_map_stats_page(enum hv_stats_object_type type, + const union hv_stats_object_identity *identity, + void **addr) +{ + int ret; + struct page *allocated_page = NULL; + + if (!addr) + return -EINVAL; + + if (mshv_use_overlay_gpfn()) { + allocated_page = alloc_page(GFP_KERNEL); + if (!allocated_page) + return -ENOMEM; + + ret = hv_call_map_stats_page2(type, identity, + page_to_pfn(allocated_page)); + *addr = page_address(allocated_page); + } else { + ret = hv_call_map_stats_page(type, identity, addr); + } + + if (ret && allocated_page) { + __free_page(allocated_page); + *addr = NULL; + } + + return ret; +} + +static int hv_call_unmap_stats_page(enum hv_stats_object_type type, + const union hv_stats_object_identity *identity) { unsigned long flags; struct hv_input_unmap_stats_page *input; @@ -868,6 +940,19 @@ int hv_call_unmap_stat_page(enum hv_stats_object_type type, return hv_result_to_errno(status); } +int hv_unmap_stats_page(enum hv_stats_object_type type, void *page_addr, + const union hv_stats_object_identity *identity) +{ + int ret; + + ret = hv_call_unmap_stats_page(type, identity); + + if (mshv_use_overlay_gpfn() && page_addr) + __free_page(virt_to_page(page_addr)); + + return ret; +} + int hv_call_modify_spa_host_access(u64 partition_id, struct page **pages, u64 page_struct_count, u32 host_access, u32 flags, u8 acquire) diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c index 288695a859f7..7684645ef00d 100644 --- a/drivers/hv/mshv_root_main.c +++ b/drivers/hv/mshv_root_main.c @@ -843,7 +843,8 @@ mshv_vp_release(struct inode *inode, struct file *filp) return 0; } -static void mshv_vp_stats_unmap(u64 partition_id, u32 vp_index) +static void mshv_vp_stats_unmap(u64 partition_id, u32 vp_index, + void *stats_pages[]) { union hv_stats_object_identity identity = { .vp.partition_id = partition_id, @@ -851,10 +852,10 @@ static void mshv_vp_stats_unmap(u64 partition_id, u32 vp_index) }; identity.vp.stats_area_type = HV_STATS_AREA_SELF; - hv_call_unmap_stat_page(HV_STATS_OBJECT_VP, &identity); + hv_unmap_stats_page(HV_STATS_OBJECT_VP, NULL, &identity); identity.vp.stats_area_type = HV_STATS_AREA_PARENT; - hv_call_unmap_stat_page(HV_STATS_OBJECT_VP, &identity); + hv_unmap_stats_page(HV_STATS_OBJECT_VP, NULL, &identity); } static int mshv_vp_stats_map(u64 partition_id, u32 vp_index, @@ -867,14 +868,14 @@ static int mshv_vp_stats_map(u64 partition_id, u32 vp_index, int err; identity.vp.stats_area_type = HV_STATS_AREA_SELF; - err = hv_call_map_stat_page(HV_STATS_OBJECT_VP, &identity, - &stats_pages[HV_STATS_AREA_SELF]); + err = hv_map_stats_page(HV_STATS_OBJECT_VP, &identity, + &stats_pages[HV_STATS_AREA_SELF]); if (err) return err; identity.vp.stats_area_type = HV_STATS_AREA_PARENT; - err = hv_call_map_stat_page(HV_STATS_OBJECT_VP, &identity, - &stats_pages[HV_STATS_AREA_PARENT]); + err = hv_map_stats_page(HV_STATS_OBJECT_VP, &identity, + &stats_pages[HV_STATS_AREA_PARENT]); if (err) goto unmap_self; @@ -882,7 +883,7 @@ static int mshv_vp_stats_map(u64 partition_id, u32 vp_index, unmap_self: identity.vp.stats_area_type = HV_STATS_AREA_SELF; - hv_call_unmap_stat_page(HV_STATS_OBJECT_VP, &identity); + hv_unmap_stats_page(HV_STATS_OBJECT_VP, NULL, &identity); return err; } @@ -990,7 +991,7 @@ free_vp: kfree(vp); unmap_stats_pages: if (hv_scheduler_type == HV_SCHEDULER_TYPE_ROOT) - mshv_vp_stats_unmap(partition->pt_id, args.vp_index); + mshv_vp_stats_unmap(partition->pt_id, args.vp_index, stats_pages); unmap_ghcb_page: if (mshv_partition_encrypted(partition) && is_ghcb_mapping_available()) hv_unmap_vp_state_page(partition->pt_id, args.vp_index, @@ -1742,7 +1743,8 @@ static void destroy_partition(struct mshv_partition *partition) continue; if (hv_scheduler_type == HV_SCHEDULER_TYPE_ROOT) - mshv_vp_stats_unmap(partition->pt_id, vp->vp_index); + mshv_vp_stats_unmap(partition->pt_id, vp->vp_index, + (void **)vp->vp_stats_pages); if (vp->vp_register_page) { (void)hv_unmap_vp_state_page(partition->pt_id, diff --git a/include/hyperv/hvgdk_mini.h b/include/hyperv/hvgdk_mini.h index af85b1c36b6e..f6e31d1c3267 100644 --- a/include/hyperv/hvgdk_mini.h +++ b/include/hyperv/hvgdk_mini.h @@ -494,6 +494,7 @@ union hv_vp_assist_msr_contents { /* HV_REGISTER_VP_ASSIST_PAGE */ #define HVCALL_GET_PARTITION_PROPERTY_EX 0x0101 #define HVCALL_MMIO_READ 0x0106 #define HVCALL_MMIO_WRITE 0x0107 +#define HVCALL_MAP_STATS_PAGE2 0x0131 /* HV_HYPERCALL_INPUT */ #define HV_HYPERCALL_RESULT_MASK GENMASK_ULL(15, 0) diff --git a/include/hyperv/hvhdk_mini.h b/include/hyperv/hvhdk_mini.h index bf2ce27dfcc5..064bf735cab6 100644 --- a/include/hyperv/hvhdk_mini.h +++ b/include/hyperv/hvhdk_mini.h @@ -177,6 +177,13 @@ struct hv_input_map_stats_page { union hv_stats_object_identity identity; } __packed; +struct hv_input_map_stats_page2 { + u32 type; /* enum hv_stats_object_type */ + u32 padding; + union hv_stats_object_identity identity; + u64 map_location; +} __packed; + struct hv_output_map_stats_page { u64 map_location; } __packed; |
