Skip to content

Commit d62313b

Browse files
Jinank Jainliuw
authored andcommitted
mshv: Introduce new hypercall to map stats page for L1VH partitions
Introduce HVCALL_MAP_STATS_PAGE2 which provides a map location (GPFN) to map the stats to. This hypercall is required for L1VH partitions, depending on the hypervisor version. This uses the same check as the state page map location; mshv_use_overlay_gpfn(). Add mshv_map_vp_state_page() helpers to use this new hypercall or the old one depending on availability. For unmapping, the original HVCALL_UNMAP_STATS_PAGE works for both cases. Signed-off-by: Jinank Jain <jinankjain@linux.microsoft.com> Signed-off-by: Nuno Das Neves <nunodasneves@linux.microsoft.com> Reviewed-by: Easwar Hariharan <easwar.hariharan@linux.microsoft.com> Signed-off-by: Wei Liu <wei.liu@kernel.org>
1 parent 19c515c commit d62313b

5 files changed

Lines changed: 115 additions & 20 deletions

File tree

drivers/hv/mshv_root.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -297,11 +297,11 @@ int hv_call_connect_port(u64 port_partition_id, union hv_port_id port_id,
297297
int hv_call_disconnect_port(u64 connection_partition_id,
298298
union hv_connection_id connection_id);
299299
int hv_call_notify_port_ring_empty(u32 sint_index);
300-
int hv_call_map_stat_page(enum hv_stats_object_type type,
301-
const union hv_stats_object_identity *identity,
302-
void **addr);
303-
int hv_call_unmap_stat_page(enum hv_stats_object_type type,
304-
const union hv_stats_object_identity *identity);
300+
int hv_map_stats_page(enum hv_stats_object_type type,
301+
const union hv_stats_object_identity *identity,
302+
void **addr);
303+
int hv_unmap_stats_page(enum hv_stats_object_type type, void *page_addr,
304+
const union hv_stats_object_identity *identity);
305305
int hv_call_modify_spa_host_access(u64 partition_id, struct page **pages,
306306
u64 page_struct_count, u32 host_access,
307307
u32 flags, u8 acquire);

drivers/hv/mshv_root_hv_call.c

Lines changed: 90 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -807,9 +807,51 @@ hv_call_notify_port_ring_empty(u32 sint_index)
807807
return hv_result_to_errno(status);
808808
}
809809

810-
int hv_call_map_stat_page(enum hv_stats_object_type type,
811-
const union hv_stats_object_identity *identity,
812-
void **addr)
810+
static int hv_call_map_stats_page2(enum hv_stats_object_type type,
811+
const union hv_stats_object_identity *identity,
812+
u64 map_location)
813+
{
814+
unsigned long flags;
815+
struct hv_input_map_stats_page2 *input;
816+
u64 status;
817+
int ret;
818+
819+
if (!map_location || !mshv_use_overlay_gpfn())
820+
return -EINVAL;
821+
822+
do {
823+
local_irq_save(flags);
824+
input = *this_cpu_ptr(hyperv_pcpu_input_arg);
825+
826+
memset(input, 0, sizeof(*input));
827+
input->type = type;
828+
input->identity = *identity;
829+
input->map_location = map_location;
830+
831+
status = hv_do_hypercall(HVCALL_MAP_STATS_PAGE2, input, NULL);
832+
833+
local_irq_restore(flags);
834+
835+
ret = hv_result_to_errno(status);
836+
837+
if (!ret)
838+
break;
839+
840+
if (hv_result(status) != HV_STATUS_INSUFFICIENT_MEMORY) {
841+
hv_status_debug(status, "\n");
842+
break;
843+
}
844+
845+
ret = hv_call_deposit_pages(NUMA_NO_NODE,
846+
hv_current_partition_id, 1);
847+
} while (!ret);
848+
849+
return ret;
850+
}
851+
852+
static int hv_call_map_stats_page(enum hv_stats_object_type type,
853+
const union hv_stats_object_identity *identity,
854+
void **addr)
813855
{
814856
unsigned long flags;
815857
struct hv_input_map_stats_page *input;
@@ -848,8 +890,38 @@ int hv_call_map_stat_page(enum hv_stats_object_type type,
848890
return ret;
849891
}
850892

851-
int hv_call_unmap_stat_page(enum hv_stats_object_type type,
852-
const union hv_stats_object_identity *identity)
893+
int hv_map_stats_page(enum hv_stats_object_type type,
894+
const union hv_stats_object_identity *identity,
895+
void **addr)
896+
{
897+
int ret;
898+
struct page *allocated_page = NULL;
899+
900+
if (!addr)
901+
return -EINVAL;
902+
903+
if (mshv_use_overlay_gpfn()) {
904+
allocated_page = alloc_page(GFP_KERNEL);
905+
if (!allocated_page)
906+
return -ENOMEM;
907+
908+
ret = hv_call_map_stats_page2(type, identity,
909+
page_to_pfn(allocated_page));
910+
*addr = page_address(allocated_page);
911+
} else {
912+
ret = hv_call_map_stats_page(type, identity, addr);
913+
}
914+
915+
if (ret && allocated_page) {
916+
__free_page(allocated_page);
917+
*addr = NULL;
918+
}
919+
920+
return ret;
921+
}
922+
923+
static int hv_call_unmap_stats_page(enum hv_stats_object_type type,
924+
const union hv_stats_object_identity *identity)
853925
{
854926
unsigned long flags;
855927
struct hv_input_unmap_stats_page *input;
@@ -868,6 +940,19 @@ int hv_call_unmap_stat_page(enum hv_stats_object_type type,
868940
return hv_result_to_errno(status);
869941
}
870942

943+
int hv_unmap_stats_page(enum hv_stats_object_type type, void *page_addr,
944+
const union hv_stats_object_identity *identity)
945+
{
946+
int ret;
947+
948+
ret = hv_call_unmap_stats_page(type, identity);
949+
950+
if (mshv_use_overlay_gpfn() && page_addr)
951+
__free_page(virt_to_page(page_addr));
952+
953+
return ret;
954+
}
955+
871956
int hv_call_modify_spa_host_access(u64 partition_id, struct page **pages,
872957
u64 page_struct_count, u32 host_access,
873958
u32 flags, u8 acquire)

drivers/hv/mshv_root_main.c

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -843,18 +843,19 @@ mshv_vp_release(struct inode *inode, struct file *filp)
843843
return 0;
844844
}
845845

846-
static void mshv_vp_stats_unmap(u64 partition_id, u32 vp_index)
846+
static void mshv_vp_stats_unmap(u64 partition_id, u32 vp_index,
847+
void *stats_pages[])
847848
{
848849
union hv_stats_object_identity identity = {
849850
.vp.partition_id = partition_id,
850851
.vp.vp_index = vp_index,
851852
};
852853

853854
identity.vp.stats_area_type = HV_STATS_AREA_SELF;
854-
hv_call_unmap_stat_page(HV_STATS_OBJECT_VP, &identity);
855+
hv_unmap_stats_page(HV_STATS_OBJECT_VP, NULL, &identity);
855856

856857
identity.vp.stats_area_type = HV_STATS_AREA_PARENT;
857-
hv_call_unmap_stat_page(HV_STATS_OBJECT_VP, &identity);
858+
hv_unmap_stats_page(HV_STATS_OBJECT_VP, NULL, &identity);
858859
}
859860

860861
static int mshv_vp_stats_map(u64 partition_id, u32 vp_index,
@@ -867,22 +868,22 @@ static int mshv_vp_stats_map(u64 partition_id, u32 vp_index,
867868
int err;
868869

869870
identity.vp.stats_area_type = HV_STATS_AREA_SELF;
870-
err = hv_call_map_stat_page(HV_STATS_OBJECT_VP, &identity,
871-
&stats_pages[HV_STATS_AREA_SELF]);
871+
err = hv_map_stats_page(HV_STATS_OBJECT_VP, &identity,
872+
&stats_pages[HV_STATS_AREA_SELF]);
872873
if (err)
873874
return err;
874875

875876
identity.vp.stats_area_type = HV_STATS_AREA_PARENT;
876-
err = hv_call_map_stat_page(HV_STATS_OBJECT_VP, &identity,
877-
&stats_pages[HV_STATS_AREA_PARENT]);
877+
err = hv_map_stats_page(HV_STATS_OBJECT_VP, &identity,
878+
&stats_pages[HV_STATS_AREA_PARENT]);
878879
if (err)
879880
goto unmap_self;
880881

881882
return 0;
882883

883884
unmap_self:
884885
identity.vp.stats_area_type = HV_STATS_AREA_SELF;
885-
hv_call_unmap_stat_page(HV_STATS_OBJECT_VP, &identity);
886+
hv_unmap_stats_page(HV_STATS_OBJECT_VP, NULL, &identity);
886887
return err;
887888
}
888889

@@ -990,7 +991,7 @@ mshv_partition_ioctl_create_vp(struct mshv_partition *partition,
990991
kfree(vp);
991992
unmap_stats_pages:
992993
if (hv_scheduler_type == HV_SCHEDULER_TYPE_ROOT)
993-
mshv_vp_stats_unmap(partition->pt_id, args.vp_index);
994+
mshv_vp_stats_unmap(partition->pt_id, args.vp_index, stats_pages);
994995
unmap_ghcb_page:
995996
if (mshv_partition_encrypted(partition) && is_ghcb_mapping_available())
996997
hv_unmap_vp_state_page(partition->pt_id, args.vp_index,
@@ -1742,7 +1743,8 @@ static void destroy_partition(struct mshv_partition *partition)
17421743
continue;
17431744

17441745
if (hv_scheduler_type == HV_SCHEDULER_TYPE_ROOT)
1745-
mshv_vp_stats_unmap(partition->pt_id, vp->vp_index);
1746+
mshv_vp_stats_unmap(partition->pt_id, vp->vp_index,
1747+
(void **)vp->vp_stats_pages);
17461748

17471749
if (vp->vp_register_page) {
17481750
(void)hv_unmap_vp_state_page(partition->pt_id,

include/hyperv/hvgdk_mini.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,7 @@ union hv_vp_assist_msr_contents { /* HV_REGISTER_VP_ASSIST_PAGE */
494494
#define HVCALL_GET_PARTITION_PROPERTY_EX 0x0101
495495
#define HVCALL_MMIO_READ 0x0106
496496
#define HVCALL_MMIO_WRITE 0x0107
497+
#define HVCALL_MAP_STATS_PAGE2 0x0131
497498

498499
/* HV_HYPERCALL_INPUT */
499500
#define HV_HYPERCALL_RESULT_MASK GENMASK_ULL(15, 0)

include/hyperv/hvhdk_mini.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,13 @@ struct hv_input_map_stats_page {
177177
union hv_stats_object_identity identity;
178178
} __packed;
179179

180+
struct hv_input_map_stats_page2 {
181+
u32 type; /* enum hv_stats_object_type */
182+
u32 padding;
183+
union hv_stats_object_identity identity;
184+
u64 map_location;
185+
} __packed;
186+
180187
struct hv_output_map_stats_page {
181188
u64 map_location;
182189
} __packed;

0 commit comments

Comments
 (0)